There are many topics with this title, but none have helped me resolve my issue. I am new to MVC and jQuery, so my guess is there is something syntactically wrong with my approach. Any help is greatly appreciated.
I have a web application where I have an upper and a lower section on my page (both divs). My goal is to select a record in the top div (user list) and have the bottom section display a list of challenge questions that the user can fill in answers for. The list below is injected in using jquery based on the record selected in the top grid. Here's the code I am using to do this.
View - javascript:
function editModeratorSecurity(aPersonId) {
$.ajax({
url: '/Admin/GetAdvSecurity/' + aPersonId,
type: 'POST',
progress: showModSearchProgress(),
success: function (result) {
AdvancedSuccess(result);
},
error: function (result) {
AdvancedFailure(result);
}
});
}
function showModSearchProgress() {
$("#ModeratorDetail").hide();
$("#progressMod").show();
}
function endModProgress() {
$("#progressMod").hide();
$("#ModeratorDetail").show();
}
function AdvancedSuccess(result) {
$('#ModeratorDetail').html(result);
endModProgress();
}
function AdvancedFailure(result) {
endModProgress();
}
Controller:
public PartialViewResult GetAdvSecurity(string id)
{
//ID is the iD from the person table
PersonModelBuilder pmb = new PersonModelBuilder(CurrentSession.AccountId);
PersonEditModel pers = pmb.GetPersonToEdit(new Guid(id));
if (pers != null)
{
AdvancedSecurityModel sec = new AdvancedSecurityModel();
UserModelBuilder umb = new UserModelBuilder();
//Need to get the ID from the login table - using the email address
UserModel selUser = umb.CurrentUser(pers.EmailAddress);
//Need to get the challenge questions/answers for the selected users
List<UserQuestionModel> theQ = umb.GetUserChallengeQuestions(selUser.LoginId);
sec.theUser = selUser;
sec.theQuestions = theQ;
return PartialView("_UserChallengeQuestions",sec);
}
else
{
return PartialView("_UserChallengeQuestions", new AdvancedSecurityModel());
}
}
So - this call to the controller returns the partial view and I am populating the list of questions using the following code in the partial view:
#model AdvancedSecurityModel
<form id="frmChallengeQuestions" class="inlineForm">
<div style="min-height: 100px; max-height: 400px;overflow: hidden" >
<table width="100%">
<tr>
<td align="right"><input type="button" value="Save Changes" onclick="ValidateAndSave()"/> </td>
</tr>
<tr>
<td>
#{
string sInstruction = "";
string isChecked="";
string isDisplay = "none";
if (Model.theUser.SecondLevelAuthReqd)
{
isChecked = "checked='true'";
isDisplay = "";
sInstruction = "<br> Please answer <strong>at least 5</strong> of the questions below to set up this feature...";
}
}
2nd Authentication <input type="checkbox" id="2ndAuth" onclick="javascript:ToggleQuestions()" #isChecked/>
<br /> Checking this means that you will be required to answer a random challenge question from the questions you answer in the<br/> list below each time you log in.
<span id="spnExplanation"></span>
<p> </p>
<div id="theQuestionsandAnswers" style="display: #isDisplay; max-height: 175px;overflow-y: scroll" >
<table width="100%">
#{
if (Model.theQuestions != null)
{
int iCount = 0;
foreach (UserQuestionModel ques in Model.theQuestions)
{
string theAnswer = "";
iCount += 1;
if (ques.UserAnswer != null)
{
NLxCommon.Encryption enc = new NLxCommon.Encryption();
theAnswer = enc.Decrypt256(ques.UserAnswer);
enc.Dispose();
enc = null;
}
<tr>
<td width="5%"> </td>
<td>#ques.QuestionText</td>
<td><input id="Answer_#iCount" type="text" value="#theAnswer" /></td>
<td>
<input id="UserQuestionId_#iCount" type="hidden" value="#ques.UserQuestionId">
<input id="QuestionId_#iCount" type="hidden" value="#ques.QuestionId">
<input id="UserId_#iCount" type="hidden" value="#Model.theUser.LoginId">
</td>
<td width="5%"> </td>
</tr>
}
}
}
</table>
</div>
</td>
</tr>
</table>
</div>
</form>
In the loop, I am naming my controls - input id="Answer_#iCount" - Where iCount is the number of the question - from 1 to x.
The input button is an attempt to save the changes I made to the answers of the questions listed. The javascript function is listed below.
var numQ = #Model.theQuestions.Count;
function ValidateAndSave() {
var NumAnswers = 0;
for (i=1;i<=numQ;i++) {
var answer = "#Answer_" + i.toString();
var theAnswer = $(answer).val();
if (theAnswer != "") {
NumAnswers += 1;
}
}
if (NumAnswers < 5) {
alert('You must answer at least 5 questions to enable this feature');
return false;
}
//Answered the right number of questions so SAVE
for (j=1;j<=numQ;j++) {
var uAnswer = "#Answer_" + j.toString();
var uUserQid= "#UserQuestionId_" + j.toString();
var uQuestionId= "#QuestionId_" + j.toString();
var uUserId = "#UserId_" + j.toString();
var theUAnswer = $(uAnswer).val();
alert(theUAnswer );
var theuUserQuestionId = $(uUserQid).val();
alert(theuUserQuestionId );
var theuQuestionid = $(uQuestionId).val();
alert(theuQuestionid);
var theuUserId = $(uUserId).val();
alert(theuUserId );
$.ajax({
url: '/admin/savechallengequestion',
type: 'POST',
data: {
UserQuestionId: theuUserQuestionId.toString(),
LoginId: theuUserId.toString(),
QuestionId: theuQuestionid.toString(),
UserAnswer: theUAnswer.toString()
},
contentType: 'application/json; charset=utf-8',
//progress: showModSearchProgress(),
success: insSuccess(data),
error: function () {
alert("error");
}
});
}
}
My goal with this was to loop through the answers, sending one ajax call per transaction .If someone could tell me how to do this in one call I'm willing to listen :)
The alerts all pop, showing the proper data, but when I get to the ajax call, the progress function gets called, but the ajax call never makes it to the server - I never even see it in Fiddler - like nothing happened. The controller method and the model expected are listed below - havent filled out the controller method yet - still trying to get this to fire.
Model:
public class UserQuestionModelSave
{
public string UserQuestionId { get; set; }
public string LoginId { get; set; }
public string QuestionId { get; set; }
public string UserAnswer { get; set; }
}
Controller:
[HttpPost]
public ActionResult SaveChallengeQuestion(UserQuestionModelSave aQuestionInfo)
{
UserModelBuilder umb = new UserModelBuilder();
if (ModelState.IsValid)
{
try
{
return Json(new { success = true });
}
catch (Exception)
{
return Json(new { success = false });
}
}
return Json(new { success = false });
}
If anyone has any ideas I would greatly appreciate it - this has stumped me for almost 2 days now....
If ajax request doesn't fire, then you should check console for javascript errors. BTW, there is no "inSuccess()" function in your code, which you use in this ajax call.
Related
Im making a page in razor pages asp.net c# where i want to show the values of the postgresql table, and when there is something new inserted you see the new updated table on the page without refreshing (live). I know that it probably has to do something with the notify and listen functions, but i could not find any good examples on the internet. I am a little stuck. Hope someone can show me a simple way of how to do it.
Here is the c# code:
public List<NotificationModel> ShowNotification()
{
var cs = Database.Database.Connector();
List<NotificationModel> not = new List<NotificationModel>();
using var con = new NpgsqlConnection(cs);
{
string query = "Select datumnu, bericht FROM notification ORDER BY datumnu DESC OFFSET 1";
using NpgsqlCommand cmd = new NpgsqlCommand(query, con);
{
cmd.Connection = con;
con.Open();
using (NpgsqlDataReader dr = cmd.ExecuteReader())
{
while (dr.Read())
{
not.Add(new NotificationModel { Datenow = ((DateTime) dr["datumnu"]).ToString("yyyy/MM/dd"), Bericht = dr["bericht"].ToString() });
}
}
con.Close();
}
}
return not;
}
And here is the html
<div class="container-fluid">
<p id ="output"></p>
<div class="col-3 bg-light">
<h5 class="font-italic text-left">Old Messages</h5>
<hr>
#foreach(var n in #Model.ShowNotification())
{
<tr>
<img class="img-fluid" src="/Images/Reservation.png"/>
<td>
#Html.DisplayFor(m => n.Datenow)
</td>
<td>
#Html.DisplayFor(m => n.Bericht)
</td>
</tr>
}
<hr>
</div>
</div>
</div>
One thing that you can do is to make ajax calls on mouse drag, first load some x number of records and show it in UI, later whenever user moves down call an ajax call on demand and send page number kind value and fetch to display on UI.
<script type="text/javascript">
$(document).ready(function () {
var serviceURL = '/ControllerName/GetData';
$.ajax({
type: "POST",
url: serviceURL,
data: param = "", //send page number here
contentType: "application/json; charset=utf-8",
dataType: "json",
success: successFunc,
error: errorFunc
});
function successFunc(data, status) {
console.log(data); // append this to your table as applicable
}
function errorFunc() {
alert('error');
}
});
</script>
public class ControlllerName : Controller
{
//
// GET: /AjaxTest/
public ActionResult Index()
{
return View();
}
public ActionResult Getdata(int pagenumber)
{//fetch here the data based on pagenumber
return Json("chamara", JsonRequestBehavior.AllowGet);
}
}
i've developed an mvc web app where i have a table with datas that i can filter with two dropdowns (one where i can select the value state of a data, and the other where i can select the value if the data is closed or not - yes/no) i can select both of them and if i press the button submit to filter it works. Now i want to implement some ajax calls like when i select a value of one of the dropdowns automatically update the result table but i can't pass the value of the dropdown to the controller, can anyone help me, thanks
<table id="tb2">
<tr>
<th>
<h4> LIST : #Html.DropDownList("stato", "ALL ")</h4>
</th>
<th>
<h4>ARCHVIED : #Html.DropDownList("closed", "ALL ")</h4>
</th>
<th>
<input type="submit" value="Filter" class="btn btn-info" />
</th>
</tr>
</table>
This is the controller:
public ActionResult Filter(string stato, string closed)
{
List<Card> cards = new List<Card>();
List<Closed> closedList = new List<Closed>();
closedList.Add(new Closed("False"));
closedList.Add(new Closed("True"));
ViewBag.stato = new SelectList(myApi.GetState(), "Name", "Name");
ViewBag.closed = new SelectList(closedList, "Id", "Name");
if ((stato != null && stato != "") || (closed != null && closed != ""))
{
foreach (var card in model)
{
if (card.IdList == stato || stato == "")
{
if (card.Closed == closed || closed == "")
{
cards.Add(card);
}
}
}
return View(cards);
}
return View(model);
}
this is my jquery
jQuery(document).ready(function ($) {
var drpdown1 = $("#Dropdown1Id");
var drpdown2 = $("#Dropdown1Id");
drpdown1.on('change', function () {
$.ajax({
type: "GET",
url: " /Select/Filter",
data: { stato: drpdown1.val(), closed: drpdown2.val() },
success: function (res) {
var dropValue1 = drpdown1.val();
var dropValue2 = drpdown2.val();
stato = dropValue1;
closed = dropValue2;
}
})
})
});
But it's not working, i'm new to ajax and need some help
Change your html give a method on button click. Give Id for both drop down and then write ajax function like bellow
function YourMethod() {
var drpdown1= $("#Dropdown1Id").val();
var drpdown2= $("#Dropdown2Id").val();
$.ajax({
type: "GET",
url: "/ControllerName/Filter",
data: { stato: drpdown1,closed:drpdown2},
success: function(res) {
//Your work here
}
})
}
I have a list of Ajax links that are created by the code below.
It displays a name with a link "remove" next to it.
When clicked, I want the name/link removed from the list.
Problem: I can only click and update the page once.
After clicking one of the Ajax links which removes it from the list,
it won't let me click another link. I click and it doesn't do anything.
If I want to click and remove another link, I have to refresh the page.
I don't really know javascript but I'm guessing it has to do with the name or id of the element being the same.
<table cellspacing="4" cellpadding="4" border="1" width="750">
#foreach (var item2 in Model.PeopleCheckBoxes)
{
if (ctr == 3)
{
#:<tr>
}
<td><img src="icon.jpg"> </td>
<td valign="middle" align="left">
#item2.Username
#item2.Username
#Ajax.ActionLink("remove", "RemoveMemberFromEvent", "GiftList",
new { eventID = #Model.catID, peopleID = #item2.Id },
new AjaxOptions
{
UpdateTargetId = "peopleTable",
InsertionMode = InsertionMode.Replace,
HttpMethod = "POST"
}, new { #class = "details2", title = "Remove person" })
</td>
if (ctr == 5)
{
#:</tr>
ctr = 2;
}
ctr++;
} </table>
[HttpPost]
public PartialViewResult RemoveMemberFromEvent(int eventID, int peopleID)
{
// removes item :
var aEvent = (from p in _EventMemberRepository.Table
// ............
_giftListService.DeletePersonOnGiftPage(aEvent);
// then update the database :
var members2 = from c in _custRepository.Table
var vModel = new GiftListItems();
//...........
return PartialView("_RemoveMemberFromEvent", vModel);
}
Is this a common problem?
I'm trying to recreate MVC Music Store but I've faced an error which I can't handle: "The ObjectContext instance has been disposed and can no longer be used for operations that require a connection". The error is related to the following line in the ShoppingCart Index view:
#Html.ActionLink(item.Product.Title, "Details", "Store", new { id = item.ProductId }, null)
ShoppingCartController:
public class ShoppingCartController : Controller
{
OnlineStoreDbContext db = new OnlineStoreDbContext();
//
// GET: /ShoppingCart/
public ActionResult Index()
{
var cart = ShoppingCart.GetCart(this.HttpContext);
var viewModel = new ShoppingCartViewModel
{
CartItems = cart.GetCartItems(),
CartTotal = cart.GetTotal()
};
return View(viewModel);
}
//
// GET: /Store/AddToCart/5
public ActionResult AddToCart(int id)
{
// Retrieve the album from the database
var addedProduct = db.Products.Single(product => product.ProductId == id);
// Add it to the shopping cart
var cart = ShoppingCart.GetCart(this.HttpContext);
cart.AddToCart(addedProduct);
// Go back to the main store page for more shopping
return RedirectToAction("Index");
}
[HttpPost]
public ActionResult RemoveFromCart(int id)
{
// Remove the item from the cart
var cart = ShoppingCart.GetCart(this.HttpContext);
// Get the name of the album to display confirmation
string productName = db.Carts.Single(item => item.RecordId == id).Product.Title;
// Remove from cart
int itemCount = cart.RemoveFromCart(id);
// Display the confirmation message
var results = new ShoppingCartRemoveViewModel
{
Message = Server.HtmlEncode(productName) + " has been removed from your shopping cart.",
CartTotal = cart.GetTotal(),
CartCount = cart.GetCount(),
ItemCount = itemCount,
DeleteId = id
};
return Json(results);
}
//
// GET: /ShoppingCart/CartSummary
[ChildActionOnly]
public ActionResult CartSummary()
{
var cart = ShoppingCart.GetCart(this.HttpContext);
ViewData["CartCount"] = cart.GetCount();
return PartialView("CartSummary");
}
}
ShoppingCart Index View:
#model OnlineStoreMVC.UI.ViewModels.ShoppingCartViewModel
#{
ViewBag.Title = "Shopping Cart";
}
<script src="/Scripts/jquery-1.4.4.min.js" type="text/javascript"></script>
<script type="text/javascript">
$(function () {
// Document.ready -> link up remove event handler
$(".RemoveLink").click(function () {
// Get the id from the link
var recordToDelete = $(this).attr("data-id");
if (recordToDelete != '') {
// Perform the ajax post
$.post("/ShoppingCart/RemoveFromCart", { "id": recordToDelete },
function (data) {
// Successful requests get here
// Update the page elements
if (data.ItemCount == 0) {
$('#row-' + data.DeleteId).fadeOut('slow');
} else {
$('#item-count-' + data.DeleteId).text(data.ItemCount);
}
$('#cart-total').text(data.CartTotal);
$('#update-message').text(data.Message);
$('#cart-status').text('Cart (' + data.CartCount + ')');
});
}
});
});
function handleUpdate() {
// Load and deserialize the returned JSON data
var json = context.get_data();
var data = Sys.Serialization.JavaScriptSerializer.deserialize(json);
// Update the page elements
if (data.ItemCount == 0) {
$('#row-' + data.DeleteId).fadeOut('slow');
} else {
$('#item-count-' + data.DeleteId).text(data.ItemCount);
}
$('#cart-total').text(data.CartTotal);
$('#update-message').text(data.Message);
$('#cart-status').text('Cart (' + data.CartCount + ')');
}
</script>
<h3>
<em>Review</em> your cart:
</h3>
<p class="button">
#Html.ActionLink("Checkout", "AddressAndPayment", "Checkout")
</p>
<div id="update-message">
</div>
<table>
<tr>
<th>
Movie Title
</th>
<th>
Price (each)
</th>
<th>
Quantity
</th>
<th></th>
</tr>
#foreach (var item in Model.CartItems)
{
<tr id="row-#item.RecordId">
<td>
#Html.ActionLink(item.Product.Title, "Details", "Store", new { id = item.ProductId }, null)
</td>
<td>
#item.Product.Price
</td>
<td id="item-count-#item.RecordId">
#item.Count
</td>
<td>
Remove from cart
</td>
</tr>
}
<tr>
<td>
Total
</td>
<td></td>
<td></td>
<td id="cart-total">
#Model.CartTotal
</td>
</tr>
</table>
Edit:
public class ShoppingCart
{
string ShoppingCartId { get; set; }
public const string CartSessionKey = "CartId";
public static ShoppingCart GetCart(HttpContextBase context)
{
var cart = new ShoppingCart();
cart.ShoppingCartId = cart.GetCartId(context);
return cart;
}
public static ShoppingCart GetCart(Controller controller)
{
return GetCart(controller.HttpContext);
}
}
This error means pretty much exactly what it says. Somewhere, you've disposed of your application context instance, and then tried to make another query with it. This happens frequently when you're misusing lazy loading and perhaps being a little over-eager with disposing your context (wrapping it in a using block) for example.
I'm not seeing any likely culprit in the code you posted but ShoppingCart.GetCart looks like a prime candidate for further investigation.
Basically, you want to do two things. First, you want to get a handle on what's actually being utilized by your action/views. If you're accessing related items to a cart, or something, then you should consider eager-loading those with Include. Second, you need to ensure that you context sticks around throughout the period it needs to be used. If you're lazy loading items in your view, and you intend to do that, then you'll need to make it last the life of the request: just don't use using and rely on the Dispose method of the controller for disposing of it.
That's generalized advice though. Since I believe your issue lies in this GetCart method, if that's actually the case, then you need to approach it slightly differently. First, you can ensure that GetCart returns a fully-baked result, that will not allow further querying. In cases where you're returning an enumerable, you can normally clear this up just by using .AsList(). Since this is likely just returning a single object, you would need to map it to a DTO or something: anything other than the actual entity class.
Your other option is to inject your context to the method. Normally, injecting into the class would be preferred, but it looks like you're dealing with a static class here. Basically, you want to allow your controller to create and dispose the context and then just pass it as a parameter to your GetCart method, so that it uses the context in the controller instead of creating its own. Depending on your applications needs, you might actually consider implementing some dependency injection framework to handle tasks like these.
i use mvc 4 and try to give my web application more dynamic. At the moment i try to split some of the views in partial views so the code gets better readable and i can better re-use parts of the application.
So now this leads me to a problem. I have a view similar to this one:
<h1>Manage department</h1>
<div id="EmployeesManagement">#Html.Action("OpenEmployeesManagement")</div>
<div id="DepartmentManagement">#Html.Action("OpenDepartmentManagement")</div>
<div id="DepartmentTumorModels">#Html.Action("OpenDepartmentModels")</div>
Each of those are partial views which get called from the controller like:
public PartialViewResult OpenDepartmentModels()
{
ViewBag.ChangeVisibility = -1;
HoDManagementModel hoDManagementModel = new HoDManagementModel { UserWithRoleModelList = azaraUserManagement.GetAllEmployesOfHoD(user.getUserId()), OrganisationUnits = azaraUserManagement.GetAllOrganisationUnitsFromHoD(user.getUserId()) };
List<ModelWithOrganisationUnit> Models = ModelManagement.SearchModelsOfDepartment(hoDManagementModel.OrganisationUnits);
return PartialView("DepartmentModels", Models);
}
Now to my problem. I have a partial view like this one:
#model List<Modelle.Models.BusinessTierObjects.Models.ModelWithOrganisationUnit>
<fieldset>
<legend>Manage the models of your department</legend>
<table class="tablesorter">
<thead>
<tr>
<th>ID</th>
<th>Name </th>
<th>Department </th>
<th>Visibility</th>
<th></th>
</tr>
</thead>
<tbody>
#foreach (var item in #Model)
{
<tr>
<td>#item.ModelId</td>
<td>#Html.ActionLink((String)item.ModelName, "Details", "Details", new { id = item.ModelId }, null)</td>
<td>#item.OrganisationUnitName</td>
#if (ViewBag.ChangeVisibility == item.ModelId)
{
<td><select name="ChangeVisibility" id="ChangeVisibility">
<option value="Department" onclick="location.href='#Url.Action("ChangeVisibility", "ManageDepartment", new {tumorModelId = item.ModelId, Visibility = 0})'">Department</option>
option value="Coop" onclick="location.href='#Url.Action("ChangeVisibility", "ManageDepartment", new { ModelId = item.ModelId, Visibility = 2 })'">Coop</option>
<option value="WWW" onclick="location.href='#Url.Action("ChangeVisibility", "ManageDepartment", new { ModelId = item.ModelId, Visibility = 3 })'">WWW</option>
</select></td>
}
else{
switch ((byte)item.Visibility)
{
case 0: <td>Department</td>; break;
case 2: <td>Coop</td>; break;
case 3: <td>WWW</td>; break;
}
}
<td><button name="button" class="button" onclick="location.href='#Url.Action("RequestChangeVisibility", "ManageDepartment", new { change = #item.ModelId })'">Change Visibility</button>
</td>
</tr>}
</fieldset>
and if i click on the last button just the partial view should be reloaded. But instead the application only show me the partial view without any layout in the browser. What have i done wrong or isnĀ“t it possible to solve my problem?
The controller action from the button is:
public PartialViewResult RequestChangeVisibility(int change)
{
ViewBag.ChangeVisibility = change;
HoDManagementModel hoDManagementModel = new HoDManagementModel { UserWithRoleModelList = azaraUserManagement.GetAllEmployesOfHoD(user.getUserId()), OrganisationUnits = azaraUserManagement.GetAllOrganisationUnitsFromHoD(user.getUserId()) };
List<ModelWithOrganisationUnit> Models = ModelManagement.SearchModelsOfDepartment(hoDManagementModel.OrganisationUnits);
return PartialView("DepartmentModels", Models);
}
The reason this happens is because you are using:
onclick="location.href='#Url.Action("RequestChangeVisibility", "ManageDepartment", new { change = #item.ModelId })'"
This will refresh the whole page to the partial view result, so you only see that partial view.
what you need to do is to do an ajax call to that controller, so you should use:
<td><button name="button" class="button" onclick="RequestChangeVisibilityAjaxCall(#item.ModelId)">Change Visibility</button>
then add the following javascript to the page:
<script>
function RequestChangeVisibilityAjaxCall(change) {
$.ajax({
url: "../ManageDepartment/RequestChangeVisibility?Change=" + change,
type: 'GET',
success: function (data) {
$('#DepartmentManagement').html(data);
}
});
}
</script>
The line:
$('#DepartmentManagement').html(data);
will use the result of the ajax call (data) to populate the div with ID DepartmentManagement - I wasnt sure where you wanted that partial view to go, so just change the ID to what ever you need it to be.
Also, the line:
url: "../ManageDepartment/RequestChangeVisibility?Change=" + change,
is the url of the controller, I think i guessed it right, but you should change this to the correct address where needed.
I hope this helps.
Martyn
[edit] a good tutorial here:
also, do some googling for "mvc jquery ajax" that should also help you understand it. Much better than I can explain it! :)