How to update Partial View without full replacement - asp.net-mvc

I have this partial view. This works, ie, when the user clicks the button, an ajax trip is made to the server, and it updates the partial view and it comes down and replaces the current div with the updated Div and shows the Promo Message.
However, it seems there should be a better way to do this. In other words, is it necessary to replace the entire partial view? Isn't there a way to send just the data up to the server, and then update just the message when it gets back, like maybe via a JSON call?
Controller:
public ActionResult ApplyPromoCode(OrderViewModel orderViewModel) {
orderViewModel.PromoMessage = "Promo has been applied";
return PartialView("PromoPartial", orderViewModel);
}
Partial View:
#model NTC.PropertySearch.Models.OrderViewModel
#using (Ajax.BeginForm("ApplyPromoCode", "OrderSummary", new AjaxOptions { InsertionMode = InsertionMode.Replace, UpdateTargetId = "promo" }))
{
<div id="promo">
<table>
<td>
#Html.LabelFor(m => m.PromoCode)
</td>
<td>
#Html.TextBoxFor(m => m.PromoCode)
</td>
<td>
#Html.ValidationMessageFor(m => m.PromoCode)
</td>
<td>
<input type="submit" value="Apply Promo Code" />
</td>
<td>
#Html.DisplayFor(m=> m.PromoMessage)
</td>
</table>
</div>
}

you can do this to
Controller
public ActionResult ApplyPromoCode(OrderViewModel orderViewModel) {
//your processing code
return Content("Promo has been applied");
}
View
#model NTC.PropertySearch.Models.OrderViewModel
#using (Ajax.BeginForm("ApplyPromoCode", "OrderSummary", new AjaxOptions { UpdateTargetId = "pcode" }))
{
<div id="promo">
<table>
<td>
#Html.LabelFor(m => m.PromoCode)
</td>
<td>
#Html.TextBoxFor(m => m.PromoCode)
</td>
<td>
#Html.ValidationMessageFor(m => m.PromoCode)
</td>
<td>
<input type="submit" value="Apply Promo Code" />
</td>
<td>
<div id="pcode"></div>
</td>
</table>
</div>
}

Instead of returning a PartialView you can always return a JSON object/array or some XML and use jQuery/JavaScript on your callback function to update the values of your input fields.
Here's an example of some code I use to return JSON from a Controller:
public ActionResult CurrentTags(int entityID)
{
Entity entity = db.Entity.Find(entityID);
var tags = from tag in entity.Tag
select new
{
id = tag.Name,
text = tag.Name
};
return this.Json(tags, JsonRequestBehavior.AllowGet);
}

Related

ASP MVC 5 Post a form from a link

I need to make a custom data grid view with multi column filtering and pagination. so i made a view model winch will encapsulate three class
IEnumerable from the data.
Filter class with some properties
Pager to holder page size, current page, total pages etc ..
Filtering working fine but pagination not :(. as i loose the view model when pressing pagination link "It seems that i need to also submit the search form"
Any one can show how i can submit the form when pressing a link.
here is my view
#model TestFilteringAndPagination.ViewModels.CarViewModel
#{
ViewBag.Title = "Home Page";
}
#*Search form*#
#using (Html.BeginForm("Index", "Home", FormMethod.Post, new { id = "frm" }))
{
#Html.HiddenFor(m => Model.Pager.CurrentPage)
#Html.HiddenFor(m => Model.Pager.PageSize)
#Html.HiddenFor(m => Model.Pager.EndPage)
#Html.HiddenFor(m => m.Pager.StartPage)
<div class="form-inline">
<div class="form-group">
<label>Car No</label>
#Html.EditorFor(x => x.Filter.CarNumber, new { #class = "form-control" })
</div>
<div class="form-group">
<label>Line name</label>
#Html.EditorFor(x => x.Filter.LineName, new { #class = "form-control" })
</div>
<button type="submit" class="btn btn-default">Search</button>
</div>
<ul class="pagination">
#for (var page = Model.Pager.StartPage; page <= Model.Pager.EndPage; page++)
{
<li class="#(page == Model.Pager.CurrentPage ? "active" : "")">
#page
</li>
}
</ul>
}
#*Data grid*#
<table class="table">
<thead>
<tr>
<th>
Car number
</th>
<th>
Car Line
</th>
</tr>
</thead>
<tbody>
#foreach (var car in Model.Cars)
{
<tr>
<td>
#Html.DisplayFor(x => car.CarNumber)
</td>
<td>
#Html.DisplayFor(x => car.LineName)
</td>
</tr>
}
</tbody>
</table>
You can install the PagedList.MVC NuGet Package, see this post for more info about how to create exactly what you want.
Sorting, Filtering, and Paging with the Entity Framework in an ASP.NET MVC Application

Model is null with Html.BeginForm() ASP.NET MVC

I encountered following problem:
user visits site, clicks "Add" and then it's sending back to Controller, Model is retrieved and send to View one more time. Inside view, I check whether Model is not null
and displays data.
#if (Model != null)
{
<div id="appInfo">
<table>
<tr>
<th>#Html.DisplayNameFor(x => Model.tytul)</th>
<th>#Html.DisplayNameFor(x => Model.kategoria.nazwa)</th>
<th>#Html.DisplayNameFor(x => Model.liczba_ocen)</th>
<th>#Html.DisplayNameFor(x => Model.avg_ocena)</th>
<th>#Html.DisplayNameFor(x => Model.typ)</th>
</tr>
<tr>
<td>#Model.tytul</td>
<td>#ViewData["kategoria"]</td>
<td>#Model.liczba_ocen</td>
<td>#Model.avg_ocena</td>
<td>#Model.typ</td>
</tr>
</table>
</div>
<div>
#using (Html.BeginForm("Confirm", "Wydawca", new { app = #Model }))
{
<input type="submit" value="Cofirm it" />
}
</div>
At the end button "Confirm it" is created and once you click it invokes Confirm Method but app variable is always null. If I set its value to anything but Model it works.
[HttpPost]
public ActionResult Confirm(aplikacja app)
{
...
}
While creating button "Confirm it" Model is not null, I checked. Do you happen to know what is going wrong?
Generated html
<form action="/Wydawca/Confirm?app=Adds.Models.aplikacja" method="post">
<input type="submit" value="Zatwierdź" />
The Html.BeginForm should wrap around all of your input elements or it has nothing to post. Change your view to this:
#if (Model != null)
{
#using (Html.BeginForm("Confirm", "Wydawca", new { app = #Model }))
{
<div id="appInfo">
<table>
<tr>
<th>#Html.DisplayNameFor(x => Model.tytul)</th>
<th>#Html.DisplayNameFor(x => Model.kategoria.nazwa)</th>
<th>#Html.DisplayNameFor(x => Model.liczba_ocen)</th>
<th>#Html.DisplayNameFor(x => Model.avg_ocena)</th>
<th>#Html.DisplayNameFor(x => Model.typ)</th>
</tr>
<tr>
<td> #Model.tytul</td>
<td>#ViewData["kategoria"]</td>
<td>#Model.liczba_ocen</td>
<td>#Model.avg_ocena</td>
<td>#Model.typ</td>
</tr>
</table>
</div>
<div>
#Html.HiddenFor(x => Model.tytul)
#Html.HiddenFor(x => Model.kategoria.nazwa)
#Html.HiddenFor(x => Model.liczba_ocen)
#Html.HiddenFor(x => Model.avg_ocena)
#Html.HiddenFor(x => Model.typ)
<input type="submit" value="Cofirm it" />
</div>
}
}
You are attempting to pass an object (#Model) as a route parameter (app). Route parameters should contain scalar values (int, string, etc), not objects. View the generated HTML source in the browser and see what the <form action=""> is being set as. Then review the concept of model binding.

Why do textboxes not clear out after clearing out Model

I have a form which is submitted via ajax to the Controller. The Controller collects the data from the Model and then creates a new ViewModel and passes it to the partial view which is then updated on the Client.
The problem is that the textboxes are not cleared out as expected. The message arrives in the View as expected, so it doesn't make sense that the TextBoxes are not cleared out.
Yet it seems to be a browser issue as this is the resulting HTML, which note, does not have anything in the value:
<input id="Address_Address1" name="Address.Address1" type="text" value="" />
Yet the user sees the value that was priorly entered.
Here is the controller:
//Process Order Here
//This should clear out the ViewModel.
order = new OrderViewModel();
order.Message = "Report Added to your cart";
return PartialView("_NewOrderPartial", order);
This is the partial View:
#model NTC.PropertySearch.Models.OrderViewModel
#using (Ajax.BeginForm("NewOrder", "Order", new AjaxOptions { InsertionMode = InsertionMode.Replace, UpdateTargetId = "neworder" }))
{
<div id="neworder">
<table>
<tr>
<th style="width: 300px;">
<h3>Enter property address below</h3>
</th>
<th style="width: 30px;"></th>
<th style="width: 300px;">
<h3>Choose your report below</h3>
</th>
</tr>
<tr>
<td>
<div class="form">
<table>
<tr>
<td>
#Html.LabelFor(m => m.Address.Address1)
</td>
<td>
#Html.TextBoxFor(m => m.Address.Address1)
</td>
<td>
#Html.ValidationMessageFor(m => m.Address.Address1)
</td>
</tr>
<tr>
<td>
#Html.LabelFor(m => m.Address.Address2)
</td>
<td>
#Html.TextBoxFor(m => m.Address.Address2)
</td>
<td>
#Html.ValidationMessageFor(m => m.Address.Address2)
</td>
</tr>
<tr>
<td>
#Html.LabelFor(m => m.Address.City)
</td>
<td>
#Html.TextBoxFor(m => m.Address.City)
</td>
<td>
#Html.ValidationMessageFor(m => m.Address.City)
</td>
</tr>
<tr>
<td>
#Html.LabelFor(m => m.Address.State)
</td>
<td>
#Html.TextBoxFor(m => m.Address.State)
</td>
<td>
#Html.ValidationMessageFor(m => m.Address.State)
</td>
</tr>
<tr>
<td>
#Html.LabelFor(m => m.Address.ZipCode)
</td>
<td>
#Html.TextBoxFor(m => m.Address.ZipCode)
</td>
<td>
#Html.ValidationMessageFor(m => m.Address.ZipCode)
</td>
</tr>
</table>
<input type="submit" value="Add Report" />
#Html.DisplayFor(m=> m.Message)
</div>
</td>
</tr>
</table>
</div>
The reason for this is because the Html helpers such as TextBox are first looking at the ModelState when binding their values and only after that in the View model. This often happens when people attempt to modify/clear some value to the view model in an HttpPost controller action. The corresponding view will use the initial POSTed value and not the value in the view model.
You should clear the ModelState as well in your controller action:
ModelState.Clear();
order = new OrderViewModel();
Alternatively if you do not want to clear the entire ModelState (although in your case this seems to be the case as you are reinitializing the entire view model) you could clear only some properties that you intend to modify:
ModelState.Remove("SomeProperty");
viewModel.SomeProperty = "some new value";

How to update different targets with MVC Ajax helper?

i'm having a hard time dealing with MVC Ajax helper and trying to refresh certain part of the page. In my code, I have a situation like this:
<div id="ajaxLoadedContent">
<table>
<tr>
<th>
<%: Html.Label("ProductId") %>
</th>
<th>
<%: Html.Label("ProductName") %>
</th>
<th>
</th>
</tr>
<% foreach (var product in Model.Products)
{
%>
<tr>
<td>
<%: direccion.ProductId %>
</td>
<td>
<%: direccion.ProductName %>
</td>
<td>
<% using (Ajax.BeginForm("EditProduct", "MyController",
new { ContainerDiv = "ShowEditProducts" },
new AjaxOptions() { UpdateTargetId = "ShowEditProducts", OnSuccess = "updatePlaceholder" }))
{%>
<%: Html.Hidden("ProductId", product.ProductId)%>
<input type="submit" value="Edit" />
<%} %>
</td>
</tr>
<% } %>
</table>
<script type="text/javascript">
function updatePlaceholder(context) {
var html = context.get_data();
var placeholder = context.get_updateTarget();
$(placeholder).html(html);
return false;
}
</script>
<div id="ShowEditProducts"></div>
</div>
Now, when I press the Edit button, then the 'Editor View' appears, but the problem is that when i Submit that form, then there are two options:
The data is OK, the changes are made, the form dissapears and the list is refreshed.
The data is NOT OK, the forms stays and the validation messages appear.
The problem is that the UpdateTargetId are different for each option.
Option 1 refreshes "ShowEditProducts", while Option 2 refreshes "ajaxLoadedContent". Also, ehe 'Edit View' contains JavaScript that is executed when the view is loaded using the "Edit" button but is not executed when the form contains errors and is re-rendered.
The code of the EditView looks like this:
<% using (Ajax.BeginForm("SubmitEdit", new AjaxOptions() { UpdateTargetId = Model.ContainerDiv}))
{%>
<script type="text/javascript">
// My JavaScript
</script>
<table>
<tr>
<td>
<%: Html.Label("Id")%></br>
<%: Html.TextBoxFor(x => x.Product.ProductId)%></br>
</td>
<td>
<%: Html.Label("Name")%></br>
<%: Html.TextBoxFor(x => x.Product.ProductName)%><
</td>
</tr>
</table>
<input type="submit" value="Save" />
<%: Ajax.ActionLink("Cancel", "EmptyView","Shared", new AjaxOptions() { UpdateTargetId = Model.ContainerDiv})%>
<% } %>
So, now my two big problems are:
1. The JavaScript of the 'Edit View' don't get executed when the the view is re-renderd.
2. How can i update one target is there are errors and another one when there are not.
Thanks
The object being replaced is being set on this line:
var placeholder = context.get_updateTarget();
So instead, you should add a condition here. Eg, instead of returning HTML directly, if you return an object that looks like this:
public class Result
{
public bool Success { get; set; }
public string Html { get; set; }
}
Then you could do something like this:
var result = response.get_response().get_object();
if (result.Success)
$("#ShowEditProducts").html(html);
else
$("#ajaxLoadedContent").html(html);
Alternatively, instead of returning a Success boolean, you could have a property for the ID of the control to replace. This would be more reusable, and might make sense if you want the decision of which control to replace to be done server-side.

binding asp.net mvc form element to complex object for posting to controller

I am trying to refactor to avoid parsing the FormCollection from the view so i changed this to pass in an strongly typed object. My form elements are the same names as the properties on the LinkUpdater Object. But when i put a breakpoint on the first link in the controller all of the properties are null.
any ideas or suggestions?
View:
<%using (Ajax.BeginForm("AddNewLink", "Links", new AjaxOptions { UpdateTargetId = "LinkList", LoadingElementId = "updating", OnSuccess = "done" }))
{ %>
<fieldset style="text-align:left">
<table>
<tr><td>Url:</td><td> <input style="width:500px" type="text" name="URL" /></td></tr>
<tr><td>Description: </td><td><input style="width:400px" type="text" name="Description" /></td></tr>
<tr><td>Tags: </td><td><input style="width:400px" id="Tags" name="tags" type="text" /></td></tr>
<tr><td><input type="submit" value="Add Link" name="submit" /></td></tr>
</table>
</fieldset>
<% } %>
Controller Post:
[AcceptVerbs(HttpVerbs.Post)]
public ActionResult AddNewLink(LinkUpdater linkUpdater_)
{
string[] tags = linkUpdater_.Tags.Replace(" ", "").Split(',');
linkRepository.AddLink(linkUpdater_.URL, linkUpdater_.Description, tags);
.....
}
LinkUpdater class:
public class LinkUpdater
{
public string URL;
public string Description;
public string Tags;
}
Model binder in MVC binds to properties, while you use fields. Change to
public string URL { get; set; }
And by the way, there're other drawbacks, like if you use private set, it will silently skip binding, too.
Is there any particular reason your are not using the strongly-typed HTMLHelpers to render your input fields?
<%using (Ajax.BeginForm("AddNewLink", "Links", new AjaxOptions { UpdateTargetId = "LinkList", LoadingElementId = "updating", OnSuccess = "done" }))
{ %>
<fieldset style="text-align: left">
<table>
<tr>
<td>
Url:
</td>
<td>
<%=Html.TextBox("URL", Model.URL, new { style = "width:500px;" }) %>
</td>
</tr>
<tr>
<td>
Description:
</td>
<td>
<%=Html.TextBox("Description", Model.Description, new { style = "width:400px;" }) %>
</td>
</tr>
<tr>
<td>
Tags:
</td>
<td>
<%=Html.TextBox("Tags", Model.Tags, new { style = "width:400px;" }) %>
</td>
</tr>
<tr>
<td>
<input type="submit" value="Add Link" name="submit" />
</td>
</tr>
</table>
</fieldset>
<% } %>
I'm not sure it will fix your problem, but it's a step in the right direction at least.

Resources