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! :)
Related
I have view with tasks. Each task has an #Ajax.Action link to add this task to check list.
My view:
#foreach (var item in Model.Tasks) {
<tr>
<td>
#Html.DisplayFor(modelItem => item.TaskText)
</td>
<td>
#Html.DisplayFor(modelItem => item.TillDate)
</td>
<td>
#Html.EnumDropDownListFor(modelItem => item.State, new { id=item.Id, #class="state"})
</td>
<td>
#Html.ActionLink("Edit", "Edit", new { id=item.Id }) |
#Html.ActionLink("Delete", "Delete", new { id = item.Id })
#Ajax.ActionLink("Add To check list", "AddToCheckList", new { id = item.Id }, new AjaxOptions { UpdateTargetId = "CheckListPartial" });
</td>
</tr>
}
My controller action:
public PartialViewResult AddToCheckList(int id)
{
context.AddTaskToCheckList(id);
return PartialView("_LoadCheckList", context.CheckList);
}
And CheckList class:
public class CheckList
{
public string Name { get; set; }
public List<Task> Tasks { get; set; } = new List<Models.Task>();
}
Now adding works, but I have a problem: I can add one task to check list several times.
How can I validate if check list contains task and show error message?
UPD:
I've make this with my controller. Validation works, but message is not shown.
public PartialViewResult AddToCheckList(int id)
{
if(context.CheckList.Tasks.Exists(t=>t.Id==id))
ModelState.AddModelError("CheckList", "Check list already contains this task.");
if (ModelState.IsValid)
{
context.AddTaskToCheckList(id);
return PartialView("_LoadCheckList", context.CheckList);
}
return PartialView();
}
Also add this string to my View:
#Html.ValidationMessageFor(model => model.CheckList)
UPD2:
My PartialView:
#model TaskTracker.Models.CheckList
<p>
#Html.ActionLink("Create New", "Create")
</p>
<table class="table">
<tr>
<th>
Текст задания
</th>
<th>
Дата выполнения
</th>
<th></th>
</tr>
#foreach (var task in Model.Tasks)
{
<tr>
<td>
#Html.DisplayFor(modelItem=>task.Value.TaskText)
</td>
<td>
#Html.DisplayFor(modelItem => task.Value.TillDate)
</td>
</tr>
}
</table>
You cannot display a ModelState error from a partial in the main view's #Html.ValidationMessageFor() - that is razor code and is parsed on the server before its sent to the view, so will display ModelState errors from the main views model only.
One option would include moving the ValidationMessageFor() to the partial view with the only drawback being the ability to position the element.
However, returning the whole table of added tasks is unnecessary when you already know all the values in the client to append the new row to the table.
Change your code to use the $.ajax methods and in the method return a JsonResult indicating success or otherwise
Html
Add To check list
Script
var url = '#Url.Action("AddToCheckList")';
var table = $('#CheckListPartial table);
$('.add').click(function() {
var id = $(this).data('id');
var cells = $(this).closest('tr').find('td');
var text = cells.eq(0).text();
var date = cells.eq(1).text();
$.post(url, { id: id }, function(result) {
if (result) {
// create and append a new row
var row = $('<tr></tr>');
row.append($(<td></td>).text(text));
row.append($(<td></td>).text(date));
table.append(row);
} else {
// display your error
}
}).fail(function (result) {
// display your error
});
})
and the controller method would be
public JsonResult AddToCheckList(int id)
{
if(context.CheckList.Tasks.Exists(t => t.Id == id))
{
return Json(null); indicate error - show a hidden element containing a message
}
context.AddTaskToCheckList(id);
return Json(true); // indicate success
}
You should also consider removing the link if successful, so the user does not accidentally click it again.
A third alternative would be to generate a checklistbox of all tasks and allow the user to select or unselect items and the post a form and save all taks inone action. Refer this answer for an example of the approach.
You can make your Tasks to be an HashSet and check in the AddTaskToCheckList method if it is already there. In that case checking is O(1)
public void AddTaskToCheckList(int id)
{
// Find task
var task = this.Tasks.Find(id);
if(!this.CheckList.Contains(task))
{
this.CheckList.Add(task);
}
else
{
// Show error message
}
}
What I want to do
I am very new to MVC.
I'm trying to create a page that allows users to perform the following actions on the same page:
View the list (table)
Add a new item (Filling the form and clicking the Add button should update the table)
Delete an item from the list (Clicking the Delete button in a row should update the table)
A simple example looks like this but I actually have two lists on one page (Fees and Costs):
Question
What would be the best way to achieve this?
Should I go with Dylan Beattie's method posted here which would look something like this?
public ActionResult MyAction(string submitButton, MyViewModel form)
{
switch (submitButton)
{
case "AddFee":
return (AddFee(form));
case "AddCost":
return (AddCost(form));
case "RemoveFee":
return (RemoveFee(form));
case "RemoveCost":
return (RemoveCost(form));
}
}
public ActionResult AddFee(MyViewModel form)
{
Fee newFee = ....; // Get entered data from `form`
_repository.InsertFee(newFee);
return View("Create"); //Back to the original page
}
Or is there any other recommended methods to handle this such as using JavaScript?
You could create the table as a partial view and re render this via ajax.
Wrap the partial view in a div and Wrap the form in #using (Ajax.BeginForm(.... and target the wrapper div. Your controller action that is targeted by the ajax request will need to return a partial view.
Here is a simple example
public class HomeController : Controller
{
public ActionResult Index()
{
MYvm vm = new MYvm() { id = 1, name = "This is my View Model" };
return View(vm);
}
public ActionResult DA(MYvm vm)
{
vm.name = "CHANGED";
return PartialView("Part", vm);
}
View:
#model MvcApplication1.Controllers.HomeController.MYvm
#{
ViewBag.Title = "Home Page";
}
#using (Ajax.BeginForm("DA", "Home", new AjaxOptions() { UpdateTargetId = "cont", HttpMethod = "Get" }))
{
<div>
Id: #Html.EditorFor(model => model.id)
</div>
<div>
Name: #Html.EditorFor(model => model.name)
</div>
<input type="submit" value="SubmitForm" />
}
<div id="cont">
#{Html.RenderPartial("part", Model);}
</div>
Partial View
#model MvcApplication1.Controllers.HomeController.MYvm
#{
ViewBag.Title = "part";
}
<h2>part</h2>
#Model.name
Should I go with [previous SO answer]
No. That answer was for a different scenario where the question had a form with two submit buttons that wanted to do two different actions (and wasn't even the accepted answer to that question).
Your sample screenshot indicates that some javascript/jquery and ajax would solve the issue cleanly.
As you're new to MVC, try to keep it relatively simple. Break up the page into separate parts:
the containing page
the edit form
the list with remove
the edit/list work independently and should be written in a way that they could be put on any other page - the page is just there to contain them and doesn't do much else (obviously your real page will contain more, but add those parts as separate components as well).
1 Create actions for your list and edit forms that return partialviews - just the parts that are needed for that view (self-contained)
controller:
[HttpGet]
public ActionResult AddCost()
{
var model = new Cost();
return PartialView(model);
}
[HttpPost]
public void AddCost(Cost model)
{
if (ModelState.IsValid) {
db.SaveCost(model);...
}
}
form Views/Home/AddCost.cshtml:
#using (Ajax.BeginForm(...
{
<div class='editor-label'>#Html.LabelFor(model=>model.Description)</div>
...etc...
}
I'll leave you to set the Ajax.BeginForm properties. But make sure the on-success calls reloadCostList() (see below)
controller
public ActionResult CostList()
{
var model = db.loadCosts(); ...
return PartialView(model);
}
list, Views/Home/CostList.cshtml
#model IEnumerable<ViewModels.Cost>
<table>
<thead>
<tr>
<th>Cost Description</th>
...
<tbody>
#foreach (var cost in Model.Costs)
{
<tr data-id='#cost.Id'>
<td>#Html.DisplayFor(x=>cost.Description)</td>
...
<td><a href='#' class='remove-button'>Remove</a></td>
}
...
2 Create an action + view for the main page with placeholder for the form and calls the list partial-action, eg:
<div id="body">
<div id="formWrapper">
#Html.Action("AddCost")
</div>
<div id="listWrapper">
#Html.Action("ListView")
</div>
</div>
if you already load the data for the page, you can pass it directly to the partial, but there's no need:
#Html.Partial("ListView", Model.Costs)
this allows you to refresh the list via an ajax call, something like:
function reloadCostList() {
$(".listWrapper").load("Home/CostList");
}
(ideally, $.ajax and add some fancy UI to indicate loading)
3 Add a remove action to your controller
[HttpPost]
public void RemoveCost(int id)
{
}
4 Wire up the Remove link
$(function() {
$(".remove-button").click(function() {
var id = $(this).closest("tr").attr("id");
$.post("/Home/RemoveCost/" + id, null, function() {
$(".listWrapper").load("Home/CostList");
// or reloadCostList(); from above
// or:
//$(".listWrapper tr[id=" + id + "]").hide();
});
});
}
rather than re-load the entire list, you could just remove the row (add some fancy UI like fade-out...)
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 have a form inside a partial view, it works but in case a server side validation error is raised it displays only the partial view. So I decided to use ajax for the submission (actually it makes sense as it is inserting a contact and there's a list in the main view).
Thing is, with the posted code if one of these errors comes it's properly displayed in the view (I'd need to make the partial visible again, but that's another thing), but if there's no error it'll display the list only in the partial view. I can do the other way round, displaying properly when there's no error but then not achieving the proper displaying of validation errors.
I would like to understand what's the best approach, or at least which are the possibilities: maybe change the code in the controller or do some kind of check in the success callback...
I edit what I had before, because when no error I should return the list, not the whole view as I posted before, but anyway I still have the doubt on how to tell one from another as both are succesfull calls to the post action
Thanks
The view is this one
#model ContactListViewModel
#{
ViewBag.Title = " My Contacts"
}
<div id="ContactList">
<h2>My Contacts</h2>
<hr />
<div id="addContainer">
#{ Html.RenderAction("AddContact"); }
</div>
<div id="editContainer" data-amp-url="#Url.Action("Edit", "Contacts")" class="initiallyHidden"></div>
#foreach (var group in Model.Contacts)
{
<div class="PlanContacts">
<div class="PlanName">#group.Key</div>
#foreach (var contact in group.Values)
{
<div class="Preview">
#Html.DisplayFor(m => contact, "Contact")
</div>
}
</div>
}
</div>
#section PageJavascript
{
<script src="~/Scripts/AMPContacts.js"></script>
}
The controller post action
[HttpPost]
public ActionResult AddContact(AddContactViewModel viewModel)
{
var partyId = (int) Session["PartyId"];
if (ModelState.IsValid)
{
_contactsManager.AddContact(viewModel, partyId);
// Here I should return the updated list
}
var newViewModel = _createBuilder.Rebuild(viewModel, partyId);
return PartialView("_AddContact", newViewModel);
}
And the ajax submission code inside the longer AMPContact.js
$('#addForm').submit(function (e) {
e.preventDefault();
var addContainer = $(document.getElementById('addContainer'));
$.ajax({
url: this.action,
type: this.method,
data: $(this).serialize(),
success: function(result) {
addContainer.html(result);
}
});
});
I understand this answer it's far from being good but maybe it's useful for somebody in terms of narrowing a possible search. As it would ended up being huge I rather post this update as an answer to my own question, not sure if it complies with good manners.
The explained one wasn't the only problem I faced, hard times as well with the reset of the form and specially the successive error submissions (once I got an error trying to submit it with errors again), so I ended up making a mess out of different solutions for different problems. Hopefully I will be able to clean it up
Thanks
In the view I use now
<div id="myContacts">
<h2>My Contacts</h2>
<hr />
<div id="addContainer">
<div class="toggler">
Add Contact
</div>
<div id="addToggling" class="initiallyHidden">
#{ Html.RenderAction("AddContact"); }
</div>
</div>
<div id="editContainer" data-amp-url="#Url.Action("Edit", "Contacts")" class="initiallyHidden"></div>
<div id="list">
#{ Html.RenderPartial("_ContactList", Model); }
</div>
In the .js
$('#addContainer').on('submit', '#addForm', ajaxCall);
function ajaxCall(e) {
e.preventDefault();
var addToggling = $(document.getElementById('addToggling'));
var contactList = $(document.getElementById('contactList'));
$.ajax({
url: this.action,
type: this.method,
data: $(this).serialize(),
success: function (result) {
if (result.passedValidation == true) {
// Json is returned with flag, we get the list from the server and update the list element
$.get(result.action, function (partial) {
contactList.html(partial);
});
// Add some effects and clear the form
$(document).scrollTop(0);
setTimeout(function () {
addToggling.slideUp(300, resetAddForm);
}, 500);
setTimeout(function () {
contactList.effect("highlight", {}, 3000);
}, 1000);
}
else {
// The form partial view is returned and displayed in the same element when there are validation errors
$(document).scrollTop(0);
addToggling.html(result);
$.validator.unobtrusive.parse('#addForm');
}
}
});
}
function resetAddForm() {
var addForm = $(document.getElementById('addForm'));
// Hhide the error messages
addForm.find("span.field-validation-error").hide();
addForm.find("div.validation-summary-errors").hide();
// Removes the class associated to errors
addForm[0].reset();
// Clear the inputs
addForm.find('input:text, input:password, input:file, select, textarea').val('');
addForm.find('input:radio, input:checkbox').removeAttr('checked').removeAttr('selected');
}
Controller with the existing action method slightly changed and a new one
public ActionResult ContactList()
{
var partyId = (int)Session["PartyId"];
var viewModel = _displayBuilder.Build(partyId);
return PartialView("_ContactList", viewModel);
}
[HttpGet]
public ActionResult AddContact()
{
var partyId = (int) Session["PartyId"];
var viewModel = _createBuilder.Build(partyId);
return PartialView("_AddContact", viewModel);
}
[HttpPost]
public ActionResult AddContact(AddContactViewModel viewModel)
{
var partyId = (int) Session["PartyId"];
if (ModelState.IsValid)
{
_contactsManager.AddContact(viewModel, partyId);
if (Request.IsAjaxRequest())
return Json(new { passedValidation = true, action = Url.Action("ContactList")});
return RedirectToAction("Index");
}
var newViewModel = _createBuilder.Rebuild(viewModel, partyId);
return PartialView("_AddContact", newViewModel);
}
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.