ViewModel not storing values when Ajax.ActionLink calling controller - asp.net-mvc

When I'm clicking ActionLink and setting ViewModel values in controller I can see changes when View being rendered. But same values comes as null into Controller when I'm clicking ActionLink second time.
How do I store the value, so it comes into controller ?
View:
#Ajax.ActionLink("Click me", "AjaxTest", "Controller", new AjaxOptions()
{
UpdateTargetId = "updatePanel",
HttpMethod = "POST",
OnSuccess = "A()"
})
<div id="updatePanel">
#Html.Partial("~/Views/Shared/_UpdatableContent.cshtml", this.Model)
</div>
Controller:
[HttpPost]
public ActionResult AjaxTest(MyViewModel model)
{
model.A = "A"
return PartialView("_UpdatableContent", model);
}
Partial view _UpdatableContent:
#Html.HiddenFor(x => x.A)
#if (Model.A == "A")
{
//Draw
}

Try adding this.Model to your ActionLink following:
#Ajax.ActionLink("Click me", "AjaxTest", "Controller", this.Model, new AjaxOptions() { UpdateTargetId = "updatePanel" })
This method passes the model back into the request, which should allow the update to happen.
Probably my biggest gripe with ASP.NET MVC is the fact that the various "Helper" functions are overloaded to the nth-degree, and not always consistently in terms of the order the arguments appear...
Hope that helps :)

I had this very same problem. Setting HttpMethod = "Post" in the AjaxOptions fixed it for me, thanks Sergejs.
My final, working code is as follows
#{
AjaxOptions ajaxOptions = new AjaxOptions
{
HttpMethod = "Post",
LoadingElementId = "product-adding-" +#Model.Product.Id,
LoadingElementDuration = 100,
OnSuccess = "AddedToCart"
};
}
<div>
#Ajax.ActionLink("Add to cart",
"AddToCart",
"Cart",
new { id = Model.Product.Id, returnUrl = Request.Url.PathAndQuery },
ajaxOptions,
new { #class = "button" })
<img id="product-adding-#Model.Product.Id" src="~/Images/ajax_loader.gif" />
</div>

Related

How can I pass a parameter together with the Model?

Here's my View (Model ActivityViewModel):
#model GPMS.Models.ActivityViewModel
<div class="tab-pane" id="managepayments" role="tabpanel">
#{ Html.RenderPartial("_Payments", Model.Payments); }
</div>
Which render a Partial (Model IEnumerable<GPMS.Models.PaymentViewModel>):
#model IEnumerable<GPMS.Models.PaymentViewModel>
#using (Ajax.BeginForm("SavePayments", "Activities", new AjaxOptions { HttpMethod = "POST", UpdateTargetId = "DynamicContainer", InsertionMode = InsertionMode.Replace, OnBegin = "AjaxBeginFormOnBegin", OnComplete = "AjaxBeginFormOnComplete", OnSuccess = "AjaxBeginFormOnSuccess", OnFailure = "AjaxBeginFormOnFailure" }))
{
#Html.AntiForgeryToken()
<!-- My Form -->
}
Which send Ajax request to my Controller's Action:
public ActionResult SavePayments(IEnumerable<PaymentViewModel> payments)
{
if (ModelState.IsValid) {
// code; here I need ActivityViewModel.ID
}
}
The question is: how can I pass to that SavePayments also my activity ID stored in ActivityViewModel.ID? Can I do with routing?
I don't want to pass the whole ActivityViewModel to SavePayments, otherwise I need to take care of its required fields for the ModelState.IsValid check.
One option is to use the overload of Html.Partial to pass the ID using additionalViewData, then retrieve it in the partial view and add it as a route value in the form.
In the main view
#{ Html.RenderPartial("_Payments", Model.Payments, new ViewDataDictionary { { "ID", Model.ID} }); }
And in the partial
#using (Ajax.BeginForm("SavePayments", "Activities", new { id = ViewData["ID"] }, new AjaxOptions { ....
Then add a parameter in the POST method for the ID
public ActionResult SavePayments(int id, IEnumerable<PaymentViewModel> payments)

Automatic Callbacks on Radio Button Changes in Ajax.Beginform ASP.net MVC

I have the following block of code in one of my Partial Pages.
Would like to know if the Ajax request can be made on change of the Radio Butto selection.
Thanks in advance.
#using (Ajax.BeginForm("_QueriesPartial", "Bug",
new AjaxOptions
{
InsertionMode = InsertionMode.Replace,
HttpMethod = "GET",
OnFailure = "searchFailed",
LoadingElementId = "ajax-loader",
UpdateTargetId = "Result",
}))
{
foreach (Query query in #Model.queries) {
<div class="radio">
#Html.RadioButton("UserQuery", query.id, new { onclick = "submitform()" })
#Html.Label(query.name, query.name)
</div>
}
}
The following works for me:
#using (Ajax.BeginForm("Action", "Controller", null,
new AjaxOptions
{
HttpMethod = "POST",
OnSuccess = "JavascriptUpdateMethod(data, target)",
Url = Url.Action("ActionAjax", "Controller")
}, new { id = AjaxFormId }))
{
#Html.Hidden("ActionMethodArg", f.Id)
<div class="radiobutton-inline">
#Html.Label("Default", new { style="width: 45px;"})
#Html.RadioButton("name", f.Id, trueorfalse,
new { onchange = "$('#AjaxFormId').trigger('submit');" })
</div>
}

MVC4 PartialViews without returning

Main view contains #Ajax.ActionLink links that updates a div target with partialViews. All works fine.
#Ajax.ActionLink("Update", "MemberInfo", new AjaxOptions() { HttpMethod = "GET", UpdateTargetId = "divCurrentView", InsertionMode = InsertionMode.Replace })
<div id="divCurrentView"></div>
Question is: When displaying a partialview and on click currently I update data and return to the same partial view that reloads the data. also reloads dropdownlists..etc `
Calling Partial View:
public PartialViewResult MemberInfo(){
.......
ViewBag.Members= new SelectList(_db.Members, "Id", "Text");
return PartialView("_MemberInfo",model);
}
[HttpPost]
public PartialViewResult MemberInfo(InformationVM model){
....... update data
//if I dont include the ViewBag again it will fail on reload
ViewBag.Members= new SelectList(_db.Members, "Id", "Text");
return PartialView("_MemberInfo",model);
}
instead of return to the same PartialView can I just show a message on the screen "data was updated" within the partial view.?
When you define your ActionLink, you can choose the element that gets replaced:
#Ajax.ActionLink("Do something", "_Methodname", new AjaxOptions {
HttpMethod = "POST",
UpdateTargetId = "StatusMessage",
InsertionMode = InsertionMode.Replace,
}, new {#class = "text-danger"})
<span id="StatusMessage"></span>
This way, the message gets loaded into the span element.
In that case, I'd include the actionlink inside the div and replace the content of the div (including the actionlink) with the partial, this time including another (different) actionlink.
<div id="divCurrentView">
#Ajax.ActionLink("Update", "MemberInfo", new AjaxOptions() { HttpMethod = "GET", UpdateTargetId = "divCurrentView", InsertionMode = InsertionMode.Replace })
</div>
Partial:
<div id="divCurrentView">
#Ajax.ActionLink("Update", "MemberInfo", new AjaxOptions {
HttpMethod = "POST", UpdateTargetId = "StatusMessage", InsertionMode = InsertionMode.Replace})
<span id="StatusMessage"></span>
</div>
That way, the second (and subsequent) clicks will POST and use the different method in the controller.

data-val attributes not generated in partialview created with Html.ActionLink in ASPNET MVC3

I've this structure
View
Html.RenderPartial (1)
Html.RenderPartial (2)
Then in each one of those Partial Views I have
#Ajax.ActionLink("Edit", "EditMethod", null, new AjaxOptions
{
HttpMethod = "POST",
InsertionMode = InsertionMode.Replace,
UpdateTargetId = "divEditContent"
}, new { #class = "my-edit" })
And when clicked it renders another partial,replacing the div "divEditContent" with something like:
public PartialViewResult EditContactInformation()
{
return PartialView("_MyEdit", GetDetails());
}
_MyEdit partial has something like:
#using (Ajax.BeginForm("SaveContactInformation", "MyBsol", new AjaxOptions
{
HttpMethod = "POST",
InsertionMode = InsertionMode.Replace,
UpdateTargetId = "divContactInformationContent"
}))
{
<script type="text/javascript">
$(function () {
$('form#ajaxForm').find('a.submit-link').click(function () {
$('form#ajaxForm').submit();
});
})
</script>
Save
#Ajax.ActionLink("Cancel", "CancelEdit", null, new AjaxOptions
HttpMethod = "POST",
InsertionMode = InsertionMode.Replace,
UpdateTargetId = "divContent"
}, new { #class = "my-cancel" })
#Html.TextBoxFor(model => model.Title, new { #class = "txt-input", placeholder = "Eg. Mr, Mrs, Ms" })
#Html.ValidationMessageFor(model => model.Title)
}
The problem is that data-val atttributes are not rendered for the input, BUT if I put the last partial (_MyEdit) where the Ajax.ActionLink (1) it DOES render them.
Is this a bug? Any workaround?
Thanks in advance! Guillermo
UPDATE
I've found something really interesting, if I go (in Chrome or Firefox with Firebug) and click on View Source I don't see data-val attributes, but if I click on Inspect Element I see them..weird...
If you want the data validation tags to be there, you need to be in a FormContext. Hence, if you're dynamically generating parts of your form, you need to include the following line in your partial view:
#{ if(ViewContext.FormContext == null) {ViewContext.FormContext = new FormContext(); }
You then need to make sure you dynamically rebind your unobtrusive validation each time you add/remove items:
$("#form").removeData("validator");
$("#form").removeData("unobtrusiveValidation");
$.validator.unobtrusive.parse("#form");

MVC Html.BeginForm using Areas

I'm using MVC areas and on a view that's in an area called "Test" I would like to have a form that posts to the following method:
area: Security
controller: AccountController
method: logon
How can I make this happen with Html.BeginForm? Can it be done?
For those of you that want to know how to get it to work with the default mvc4 template
#using (Html.BeginForm("LogOff", "Account", new { area = ""}, FormMethod.Post, new { id = "logoutForm" }))
Try this:
Html.BeginForm("logon", "Account", new {area="Security"})
Try specifying the area, controller, action as RouteValues
#using (Html.BeginForm( new { area = "security", controller = "account", action = "logon" } ))
{
...
}
Use this for area with HTML Attributes
#using (Html.BeginForm(
"Course",
"Assign",
new { area = "School" },
FormMethod.Get,
new { #class = "form_section", id = "form_course" }))
{
...
}
#using (Html.BeginForm("", "", FormMethod.Post, new { id = "logoutForm", action = "/Account/LogOff" }))
{#Html.AntiForgeryToken()
<a class="signout" href="javascript:document.getElementById('logoutForm').submit()">logout</a>
}
For Ajax BeginForm we can use this
Ajax.BeginForm("IndexSearch", "Upload", new { area = "CapacityPlan" }, new AjaxOptions { HttpMethod = "POST", InsertionMode = InsertionMode.Replace, UpdateTargetId = updateTarget }, new { id = "search-form", role = "search" })

Resources