ASP.net MVC 5 partial view Ajax POST not updating just the partial - ajax

I have a partial view that is not updating just the partial, it redirects to the action for the entire page.
In the partial view, _registerAccount.cshtml, that contains a post request to register, the request is made via Ajax in a view named _registerAccount as so:
#model LoginDemo.Models.LdapAccountModel
#using (Ajax.BeginForm("RegisterLdapAccount", "Account", new AjaxOptions
{
HttpMethod = "Post",
InsertionMode = InsertionMode.Replace
}))
{
#Html.ValidationSummary()
#Html.LabelFor(x => Model.Email) #Html.TextBoxFor(x => Model.Email, new { id = "reg-ytu-email" })
<br />
#Html.LabelFor(x => Model.Password) #Html.PasswordFor(x => Model.Password, new { id = "reg-pw" })
<input type="submit" value="Register" class="btn" />
}
In the parent page, Register.cshtml I have:
#model LoginDemo.Models.RegisterModel
...
<div class="panel hide register-type register-ytu">
#Html.Partial("_registerAccount")
</div>
In the Account Controller the ajax request goes to the RegisterAccount action:
[HttpPost]
public async Task<ActionResult> RegisterLdapAccount(LdapAccountModel model)
{
if (model.exists()) // pseudo code
{
return Json(new {foo: "bar"}); // return address to redirect to
}
else
{
ModelState.AddModelError("", "You must have a valid account.");
return PartialView(model); // return error
}
}
The problem I have is that whatever gets returned wipes out the entire page as opposed to updating just the partial within the parent page. That is, if successful the JSON return only returns the JSON, if failed the partial view return only returns the partial.
n.b. I have <add key="UnobtrusiveJavaScriptEnabled" value="true" /> in my web.config.

Amend the following code as follows:
#using (Ajax.BeginForm("RegisterLdapAccount", "Account", new AjaxOptions
{
HttpMethod = "Post",
InsertionMode = InsertionMode.Replace,
UpdateTargetId = "updatearea",
Amend the div to add the id:
<div id="updatearea" class="panel hide register-type register-ytu">
#Html.Partial("_registerAccount")
</div>
Now make sure you have unobtrustive ajax as a script on the page if you don't already.
<script type="text/javascript" src="#Url.Content("/scripts/jquery.unobtrusive-ajax.min.js")"></script>
To add this script it must be in the scripts folder for your project.
Amend the controller so that you are loading the correct partial view, if you don't state the name of the partial view the partial view loaded will be whatever matches the name of the action, if no partial view matches the name of the action no partial view will be loaded. So explicitly state which partial view you want to load like this:
return PartialView("_RegisterAccount", model)

Related

Load/Refresh only part of a page (View) using AJAX in ASP.NET MVC

I am trying to achieve the same result as mentioned by the OP in this post However when I try to render partial view by checking if it was an AJAX request in my Index action, its evaluating to false.
My Index View:
#using (Ajax.BeginForm("Index", "Home",
new AjaxOptions()
{
HttpMethod = "GET",
InsertionMode = InsertionMode.Replace,
UpdateTargetId = "restaurantList"
}))
{
<input type="search" name="searchTerm" />
<input type="submit" value="Search By Name" />
}
#Html.Partial("_Restaurant",Model)
My Partial View:
<div id="restaurantList" style="border:2px dotted red; padding-left:2em; margin-top:4px;">
#foreach (var item in Model)
{
<div>
<h4>#item.Name</h4>
<div>#item.City, #item.Country</div>
<div>#item.CountOfReviews</div>
<hr />
</div>
}
</div>
My Index Action:
public ActionResult Index(string searchTerm = null)
{
var model = ...//Building model object here
if (Request.IsAjaxRequest())
{
return PartialView("_Restaurant", model);
}
return View(model);
I would prefer not to dive into use of any jQuery or javascript as I am in the process of learning ASP.NET MVC, and would want to know why the approach I took is not working? The second answer by Dennis, in the post that I referenced also suggested similar approach.
Could someone kindly tell me what I am doing wrong?
Thanks
This is just an example how you can load view from AJAX without page refresh, it may help you.
It send text value to controller by ajax call and load that value in other view which replace main view, if you don't want to replace main view then you can take other div instead same div to load content.
Controller:
public ActionResult Index()
{
return View();
}
[HttpPost]
public PartialViewResult TestAjax(string Name)
{
ViewBag.Name = Name;
return PartialView();
}
Index.cshtml:
<input type="button" id="btnSearch" class="btn btn-warning" style="height:35px;width:120px" value="Search"/>
<label>Name:</label><input type="text" id="txtName" name="txtName" />
<script>
$('#btnSearch').click(function () {
$.ajax({
url: '#Url.Action("TestAjax", "Home")',
data: { Name: $("#txtName").val() },
type: 'POST',
success: function (data) {
$("#divContent").html(data);
}
});
});
</script>
TestAjax.cshtml:
#ViewBag.Name
As #StephenMuecke pointed out in his comments, the libraries not being loaded correctly was the problem. While creating a new bundle of all libraries and adding it in the BundkeConfig.cs I had missed ~/Scripts/jquery.unobtrusive-ajax.js*. Got it working now.

Ajax.BeginForm ignores action and controller defined in parameters in MVC 5

I am using attribute routing for get action of the page. But when I post it, ajax form ignores action and controller which I defined in parameters and tries to post to same url with get method.
This is my get action:
[AllowAnonymous]
[HttpGet]
[Route("path")]
public ActionResult Action()
{
return View();
}
This is my post action:
[AllowAnonymous]
[HttpPost]
public JsonResult Action(Model model)
{
return Json(true);
}
This is my view:
#using (Ajax.BeginForm("Action", "Controller", new AjaxOptions() { HttpMethod = "POST", UpdateTargetId = "someDiv" }))
{
#SomeInput
<input type="submit" value="send" />
}
This the generated HTML:
<form action="/path" data-ajax="true" data-ajax-method="POST" data-ajax-mode="replace" data-ajax-update="#someDiv" id="form0" method="post">
<input value="submit" type="submit">
</form>
When the button is clicked. A post to domain/path is firing. Why the action I defined is ignored?
I was able to solve this issue by adding a null RouteValues after the Controller/ Action:
#using (Ajax.BeginForm("Action", "Controller", null, new AjaxOptions() { HttpMethod = "POST", UpdateTargetId = "someDiv" }))
{
#SomeInput
<input type="submit" value="send"/>
}
In my example I have an EditorTemplate with its own Ajax.BeginForm defined. When I render that EditorTemplate from within a DisplayTemplate it overrides the child EditorTemplate's Controller destination to the one the parent DisplayTemplate uses, however it keeps the same Action. So it looks like, at least in my instance, the RouteValues was being overridden if not provided.
routes.MapRoute(
name: "Any Name",
url: "Any URL",
defaults: new { Controller = "Your Ajax Controller Name ", action = "Your Ajax action Name" }
);
Or Try This
routes.MapRoute(
name: "Default",
url: "{controller}/{action}/{id}",
defaults: new { controller = "Home", action = "Index", id = UrlParameter.Optional }
);
Add this to the last of all routes in RouteConfig.cs

How to submit entire form to MVC Controller Action using DataTables Ajax

I'm revisiting a problem I had early on with a page that contains quite a few input and select controls in a form. I prefer that my Controller Action uses the View Model to determine the input values, but the model's members are always empty when submitted. Here is my undesirable WORKING code, briefly:
VIEW MODEL:
public class MyViewModel
{
[Display(Name = "Project Name")]
public string ProjectName { get; set; }
[Display(Name = "Project Country")]
public string ProjectCountry { get; set; }
public IEnumerable<SelectListItem> Countries { get; set; }
}
RAZOR VIEW:
#model My_Web_App.Models.MyViewModel
#using (Html.BeginForm(null, null, FormMethod.Post, new { id = "myform" }))
{
#Html.AntiForgeryToken()
#Html.ValidationSummary(true, "", new { #class = "text-danger" })
<div class="form-group">
#Html.LabelFor(model => model.ProjectName)
<div class="col-md-9">
#Html.EditorFor(model => model.ProjectName)
</div>
</div>
<!-- Project Country -->
<div class="form-group">
#Html.LabelFor(model => model.ProjectCountry)
<div class="col-md-4">
#Html.DropDownListFor(
x => x.ProjectCountry,
new SelectList(Model.Countries, "Value", "Text"))
</div>
</div>
<table id="mytable">
<thead>
<tr>
<th>Data1</th>
<th>Data2</th>
<th>Data3</th>
</tr>
</thead>
<tbody></tbody>
</table>
<button id="btnSubmit" type="submit">Submit</button>
}
<script type="text/javascript">
$('#btnSubmit').click(function (event) {
event.preventDefault();
oTable = $('#mytable').dataTable({
"ajax": {
"url": "/MyController/MyJsonResult/",
"type": "POST",
"data": {
ProjectName: $('#ProjectName').val(),
ProjectCountry: $('#ProjectCountry').val()
}
}
});
return false;
});
</script>
CONTROLLER:
[AcceptVerbs(HttpVerbs.Post)]
public JsonResult MyJsonResult()
{
string projectName = Request["ProjectName"];
string projectCountry = Request["ProjectCountry"];
... DO SOMETHING ...
return Json(new { data = dosomethingresult }, JsonRequestBehavior.AllowGet);
}
The above code works in that I can get the View's form variables and use them to determine the results to return. Obviously I've left out a lot of code, a lot of form variables, and a lot of controller logic. I don't want to convert strings to integers, worry about whether a POST var is empty or null, etc. There are so many form variables I would like MVC to take care of this for me. For example:
PREFERRED CONTROLLER ACTION:
[AcceptVerbs(HttpVerbs.Post)]
public JsonResult MyJsonResult(MyViewModel model)
{
string projectName = model.ProjectName;
string projectCountry = model.ProjectCountry;
... DO SOMETHING ...
return Json(new { data = dosomethingresult }, JsonRequestBehavior.AllowGet);
}
The problem with the preferred controller action above is that the contents of model are always null when using DataTables Ajax.
model is initialized with valid data if I make the Ajax call outside of the DataTables initialization. :
$('#btnSubmit').click(function (event) {
event.preventDefault();
$.ajax({
url: "/MyController/MyJsonResult/",
type: "POST",
dataType: "json",
data: $('#myform').serialize()
});
return false;
}
The data setting just above correctly serializes all of the form fields and MVC successfully creates the View Model object for me to use in the Controller Action. Unfortunately, "data": $('#myform').serialize() in the DataTables Ajax does not work. The model is uninitialized (nulls and zeros) when the Controller Action is called.
How can I pass my entire form to the Controller Action using DataTables Ajax so that my View Model object contains correct data from the View's form?
I have been searching for a solution for a long time. Way too long. :S
Try this in your Razor view:
#using (Html.BeginForm("MyJsonResult", "MyController", FormMethod.Post, new { id = "myform" }))

Saving multiple partial views from one main page

Here is my requirement :
I am designing a page to add a vehicle to the database :
Normal vehicle information [Model - Inventory]
Some other features [Model - IList]
Here is my index.cshtml page
#model Model.ViewModel.VehicleViewModel
<div>
<div class='col-md-12'>
<div class="form-group">
<input id="mainFormSubmit" type="button" value="Save" class="btn btn-default" />
</div>
</div>
#{Html.RenderPartial("~/Views/Shared/_InventoryPartial.cshtml", Model.InventoryVM);}
#{Html.RenderPartial("~/Views/Shared/_StandardFeaturePartial.cshtml", Model.StandardFeatures);}
</div>
<script type="text/javascript">
$('#mainFormSubmit').click(function () {
$('#InventoryForm').submit();
$("#StandardFeatureForm").submit();
});
</script>
This is my view model class
public class VehicleViewModel
{
public InventoryViewModel InventoryVM { get; set; }
public IList<StandardFeature> StandardFeatures { get; set; }
}
The Inventory partial view [_InventoryPartial.cshtml]
#model Model.ViewModel.InventoryViewModel
#{
var options = new AjaxOptions() { HttpMethod = "Post" };
}
<div class="container">
<div class="row">
<div class="col-md-12">
#using (Ajax.BeginForm("InventorySave", "AddVehicle", options, new { id = "InventoryForm" }))
{
<fieldset>
<legend>Inventory Info</legend>
<div class='col-md-6'>
<!-- VIN input-->
<div class="form-group">
#Html.LabelFor(x => x.VIN, new { #class = "col-md-4 control-label" })
<div class="col-md-7">
#Html.TextBoxFor(x => x.VIN, new { #class = "form-control", #placeholder = "VIN" })
</div>
</div>
</div>
</fieldset>
}
The standard feature partial view [_StandardFeaturePartial.cshtml]
==
#model IEnumerable<Model.DomainModel.StandardFeature>
#{
var options = new AjaxOptions() { HttpMethod = "Post" };
}
<div class="container">
<div class="row">
<div class="col-md-12">
#using (Ajax.BeginForm("StandardFeatureSave", "AddVehicle", options, new { id = "StandardFeatureForm" }))
{
When I am clicking on index page SAVE button, only
$('#InventoryForm').submit();
$("#StandardFeatureForm").submit();
last one(StandardFeatureForm) is executing.
Please let me know if this process is correct, and what could be the reason of this issue.
You should not call the submit method twice. Depending of the browser you can face different issues :
the form submission causes the browser to navigate to the form action and the submission
of the first may prevent the submission of the second
The browser could detected there are two requests and discards the
first submit.
In your case it will be easier to wrap your two partial views inside a unique form.
#using (Ajax.BeginForm("InventorySave", "AddVehicle", FormMethod.Post, new { id = "InventoryForm" }))
{
#{Html.RenderPartial("~/Views/Shared/_InventoryPartial.cshtml", Model.InventoryVM);}
#{Html.RenderPartial("~/Views/Shared/_StandardFeaturePartial.cshtml", Model.StandardFeatures);}
}
However when the partial views render they are not generating the correct name attributes for the larger modelModel.ViewModel.VehicleViewModel you want to use :
public void InventorySave(VehicleViewModel vehicleViewModel) {}
In this case you should use EditorTempmlate instead of partial views. It's simple to do from your partial views and this post should help you :Post a form with multiple partial views
Basically, drag your partials to the folder ~/Shared/EditorTemplates/
and rename them to match the model name they are the editor templates
for.
Finally something like :
#model Model.ViewModel.VehicleViewModel
#using (Html.BeginForm("InventorySave", "AddVehicle", FormMethod.Post, new { id = "InventoryForm" }))
{
#Html.EditorFor(m => m.InventoryVM);
#Html.EditorFor(m => m.StandardFeatures});
}
The Ajax.BeginForm helper already has a submit event associated to it which creates an Ajax POST request. When you are manually submitting your form using $('#InventoryForm').submit();, you're calling both and the submit events which can have strange side effects.
There are a few ways around this. Here is one solution
Change your forms to a regular HTML form using the Html.BeingForm helper.
Amend your script to create ajax requests and use the form data
$('#InventoryForm').submit(function(e) {
e.preventDefault();
$.post($(this).attr("action"), $(this).serialize(), function(r) {
//Do something
});
});
$('#StandardFeatureForm').submit(function(e) {
e.preventDefault();
$.post($(this).attr("action"), $(this).serialize(), function(r) {
//Do something
});
});
Hope this helps

MVC3 Razor Ajax Form Submit

I use The MVC3 Helper to generate my Ajax form like this:
#using (Ajax.BeginForm("Attended", "Lesson", new AjaxOptions
{
HttpMethod = "GET",
InsertionMode = InsertionMode.InsertAfter,
UpdateTargetId = "mdl" + item.ID
}))
{
#Html.HiddenFor(modelItem => item.ID);
#Html.CheckBox("Attended", item.Attended, new { OnChange = "javascript:this.form.submit()"});
}
I just don't find the proper way to submit the Form on the change event of the checkbox.
I don't want my users to click the submit button.
The HTMLAttribute works, but on the change a postback happens instead of an ajax request.
Does anybody know the answer?
First, create a submit button inside your form, and hide it by setting the attribute style="display:none;". Then, instead of using this.form.submit() in your onchange event, use the following:
$(this).parents('form:first').find(':submit')[0].click();
This will invoke the jquery.unobtrusive-ajax.js script, and complete your Ajax submission.
this may help
#Html.CheckBox("Attended", item.Attended, new { OnChange = "submitForm"});
function submitForm(e)
{
document.forms[0].submit();
}
What about using jQuery to trigger the submit? Like in this answer How to post ASP.NET MVC Ajax form using JavaScript rather than submit button
Using the .change() event instead of the .click() event the jQuery part would look something like this:
$(function() {
$('form#ajaxForm').find('input.submit').change( function() {
$('form#ajaxForm').trigger('submit');
});
}
#using (Ajax.BeginForm("Attended", "Lesson", new { id = Model.Id }, new AjaxOptions
{
HttpMethod = "GET",
InsertionMode = InsertionMode.InsertAfter,
UpdateTargetId = "mdl" + item.ID
}, new { id = "ajaxForm" } ))
{
#Html.HiddenFor(modelItem => item.ID);
#Html.CheckBox("Attended", item.Attended, new { #class = "submit"});
}
This is totally untested code so beware of typos :)
Forms are the classical way of sending a request - therefore it is POST - your GET setup is overruled by that in onChange - submits will always clear the content and replaced with server content - i do some javascript to send using AJAX - cannot see that, so I presume that it does exactly that. your OnChange should execute this AJAX function instead ...
Hmm, what actually worked for me, even on cell phones, which was a problem area, was the following, in my cshtml file for a Partial View. It also includes code to grey out the button and write "Saving..." until the view posts back, which avoids people pounding on the submit button when they get impatient for slow SQL Servers.
<div id="myFutureDayEdit">
<script type="text/javascript">
$(document).ready(function () {
$("#submitFutureDayEditVisibleButton").click(function () {
$(this).prop('disabled', true);
$("#myUserMessage").html("Saving...");
$("#myUserMessage").show();
document.getElementById("submitFutureDayEditHiddenButton").click();
});
});
</script>
#Html.ValidationSummary(true)
#using (Ajax.BeginForm("SaveFutureDayEdit", "Member", new AjaxOptions { InsertionMode = InsertionMode.Replace, UpdateTargetId = "myFutureDayEdit" }))
{ ... bla bla bla
and
<input id="submitFutureDayEditVisibleButton" type="button" value="Save Changes" />
<input id="submitFutureDayEditHiddenButton" style="display:none;" type="submit" value="SC" />
<div id="myUserMessage">
#if (Model.UserMessage != null)
{ #Model.UserMessage }
</div>
<input type="hidden" id="bUnsavedChanges" name="bUnsavedChanges" value="false" />
}
</div>
<div id="hahuloading">
<div id="hahuloadingcontent">
<p id="hahuloadingspinner">
Saving...
</p>
</div>
</div>

Resources