I am using MVC Structure. I have to create a report which can be filtered by drop downs. I am thing to use a partial view to display report.
HEre is the structure of the page I want to achieve.
On top of page, there will be some drop down lists.
Below these will be page for report.
when user changes the options from dropdownlist, the report will be filtered.
I have two questions
1. How to render partial page.
2. How to refresh partial page through ajax/jquery. I want to do this on client side.
I have checked online, I am rendering page as shown in code below
VIEW
<h3>Report</h3>
<div>
<table>
<tr>
<td>ServiceLine</td>
<td>#Html.DropDownList("ServiceLine", null, new {id="ServiceLine"}) </td>
</tr>
</table>
</div>
<div>
<h2>List</h2>
<div>
#Html.Partial("PartialView")
</div>
</div>
This is what I have got in controller
public ActionResult PortfolioReport(char serviceLine)
{
//Department List
var serviceLines = Enum.GetValues(typeof(SogetiDepartments)).Cast<SogetiDepartments>().Select(v => new SelectListItem
{
Text = v.ToString(),
Value = ((char)v).ToString(),
});
foreach (SelectListItem item in serviceLines)
{
if (Convert.ToChar(item.Value) == serviceLine)
item.Selected = true;
}
ViewBag.ServiceLine = serviceLines;
return View();
}
Any kind of help is appreciated.
You have to use jQuery to achieve this feature
First apply some identifier to your data container
<div id="reportContent">
#Html.Partial("PartialView")
</div>
And then write script on your dropdown change event using jQuery
<script type="text/javascript">
$(function(){
$("#ServiceLine").change(function{
// get data from server using ajax
var url = 'YourPartialPageURL?'+serviceLine+="="+$(this).val();
$('#reportContent').load(url);
});
});
</script>
Note: You should use return PartialView(); from your controller action
And don't use #Html.Partial and use #Html.Action instead.
#Html.Partial loads View directly without going to Controller Action.
It should be used if you have data to be passed with you or if you just want to load some static content on the page
Hoping someone can help me solve this issue.
I'm using Ajax.BeginForm quite often when I need to update a part of my actual webpage. But if I have a second button in the web form where I need go to a complete different page, and for example do a search and get some values that I need to complete the form. The page turns up in the update panel (updateTargetID) instead of in a complete new View. That is happening even id a do a RedirectToAction in the controller. Of course the ajax.beginform does what I accept it to do, in other words update the panel that shall be updated. But is there a way to get ajax.Beginform to use redirectToaction without updating when the user is choosing to do for example a search instead of sending the form?
I'm working with asp.net MVC,
Problem;
<% using (Ajax.BeginForm(new AjaxOptions() { LoadingElementId = "loadingElement", UpdateTargetId = "SearchResult", InsertionMode = InsertionMode.Replace}))
{%>
<% Html.RenderPartial("Searchfields", Model); %>
<div>
<%:Html.ActionLink("blank", "Index")%>
</div>
<div id="loadingElement" style="display: none">
Load data...
</div>
<div id="SearchResult">
<% if (Model.SearchResult != null)
{
Html.RenderPartial("SearchResult", Model.SearchResult);
} %>
</div>
<% } %>
In the controller (post) I do this among other stuff;
if (Request.IsAjaxRequest())
{
return PartialView("SearchResult", data.SearchResult);
}
But before this I need to do:
if (data.SearchResult.Count() == 1)
{
return RedirectToAction("Edit", "Person", new { Id = data.SearchResult.First).Id});
}
but ofcourse if I do that the hole page i rendered in the corresponding updateTargetId,
I need to render a new view instead. So how can I for exampel use javascript to redirect oncomplete and have the values from the model sent to the script to for exampel do a window.location.replace?
I'm struggling with javascript, so please help me!
I'm used to the ASP.NET Webforms easy way of doing AJAX with UpdatePanels. I understand the process is much more artisanal with MVC.
In a specific case, I'm using Data Annotations to validate some form inputs. I use the HTML.ValidationMessageFor helper to show an error message. If I want to use AJAX to post this form and show this error message, what would be the process? Is it possible to keep the HTML.ValidationMessageFor and make it work with AJAX?
Thank you.
Are you using the built-in AJAX methods? For example, are you created the AJAX form with Ajax.BeginForm(...)? If so, it's very easy to show validation messages.
One more thing: do you want to display a validation message for each individual incorrect control, or do you just want to have a validation summary above your form? I'm pretty sure you're asking about displaying an individual message for each control, but I'll include both just in case.
To display an individual message for each incorrect control:
First, you need to put your form inputs inside a Partial View. I'll call that Partial View RegisterForm.ascx.
Next, you should have something like this in your view:
<% using (Ajax.BeginForm("MyAction", null,
new AjaxOptions {
HttpMethod = "POST",
UpdateTargetId = "myForm"
},
new {
id = "myForm"
})) { %>
<% Html.RenderPartial("RegisterForm"); %>
<% } %>
Finally, your Controller Action should look something like this:
[AcceptVerbs(HttpVerbs.Post)]
public ActionResult MyAction(CustomViewModel m)
{
if(!m.IsValid) //data validation failed
{
if (Request.IsAjaxRequest()) //was this request an AJAX request?
{
return PartialView("RegisterForm"); //if it was AJAX, we only return RegisterForm.ascx.
}
else
{
return View();
}
}
}
To display only a validation summary above your form:
You should first create a separate ValidationSummary Partial View. Here's what the code of ValidationSummary.ascx should look like:
<%# Control Language="C#" Inherits="System.Web.Mvc.ViewUserControl" %>
<%= Html.ValidationSummary("Form submission was unsuccessful. Please correct the errors and try again.") %>
Next, inside your view, you should have something like this:
<div id="validationSummary">
<% Html.RenderPartial("ValidationSummary"); %>
</div>
<% using (Ajax.BeginForm("MyAction", new AjaxOptions { HttpMethod = "POST", UpdateTargetId = "validationSummary" })) { %>
<!-- code for form inputs goes here -->
<% } %>
Finally, your Controller Action should resemble this:
[AcceptVerbs(HttpVerbs.Post)]
public ActionResult MyAction(CustomViewModel m)
{
if(!m.IsValid) //data validation failed
{
if (Request.IsAjaxRequest()) //was this request an AJAX request?
{
return PartialView("ValidationSummary"); //if it was AJAX, we only return the validation errors.
}
else
{
return View();
}
}
}
Hope that helps!
This article might be helpful:
ScottGu's blog: ASP.NET MVC 2: Model Validation.
The validation used in MVC can be both client and server side. To enable client-side validation use the:
<% Html.EnableClientValidation(); %>
declaration somewhere in your view. This negates the need to use AJAX to post your form to the server and then display the results inline, as users with javascript enabled will have their own clientside validation.
Now I've seen some questions like this, but it's not exactly what I want to ask, so for all those screaming duplicate, I apologize :).
I've barely touched ASP.NET MVC but from what I understand there is no ViewState/ControlState... fine. So my question is what is the alternative to retaining a control's state? Do we go back to old school ASP where we might simulate what ASP.NET ViewState/ControlState does by creating hidden form inputs with the control's state, or with MVC, do we just assume AJAX always and retain all state client-side and make AJAX calls to update?
This question has some answers, Maintaining viewstate in Asp.net mvc?, but not exactly what I'm looking for in an answer.
UPDATE: Thanks for all the answers so far. Just to clear up what I'm not looking for and what I'm looking for:
Not looking for:
Session solution
Cookie solution
Not looking to mimic WebForms in MVC
What I am/was looking for:
A method that only retains the state on postback if data is not rebound to a control. Think WebForms with the scenario of only binding a grid on the initial page load, i.e. only rebinding the data when necessary. As I mentioned, I'm not trying to mimic WebForms, just wondering what mechanisms MVC offers.
The convention is already available without jumping through too many hoops. The trick is to wire up the TextBox values based off of the model you pass into the view.
[AcceptVerbs(HttpVerbs.Get)]
public ActionResult CreatePost()
{
return View();
}
[AcceptVerbs(HttpVerbs.Post)]
public ActionResult CreatePost(FormCollection formCollection)
{
try
{
// do your logic here
// maybe u want to stop and return the form
return View(formCollection);
}
catch
{
// this will pass the collection back to the ViewEngine
return View(formCollection);
}
}
What happens next is the ViewEngine takes the formCollection and matches the keys within the collection with the ID names/values you have in your view, using the Html helpers. For example:
<div id="content">
<% using (Html.BeginForm()) { %>
Enter the Post Title: <%= Html.TextBox("Title", Model["Title"], 50) %><br />
Enter the Post Body: <%= Html.TextArea("Body", Model["Body"]) %><br />
<%= Html.SubmitButton() %>
<% } %>
</div>
Notice the textbox and textarea has the IDs of Title and Body? Now, notice how I am setting the values from the View's Model object? Since you passed in a FormCollection (and you should set the view to be strongly typed with a FormCollection), you can now access it. Or, without strongly-typing, you can simply use ViewData["Title"] (I think).
POOF Your magical ViewState. This concept is called convention over configuration.
Now, the above code is in its simplest, rawest form using FormCollection. Things get interesting when you start using ViewModels, instead of the FormCollection. You can start to add your own validation of your Models/ViewModels and have the controller bubble up the custom validation errors automatically. That's an answer for another day though.
I would suggest using a PostFormViewModel instead of the Post object, but to each-his-own. Either way, by requiring an object on the action method, you now get an IsValid() method you can call.
[AcceptVerbs(HttpVerbs.Post)]
public ActionResult CreatePost(Post post)
{
// errors should already be in the collection here
if (false == ModelState.IsValid())
return View(post);
try
{
// do your logic here
// maybe u want to stop and return the form
return View(post);
}
catch
{
// this will pass the collection back to the ViewEngine
return View(post);
}
}
And your Strongly-Typed view would need to be tweaked:
<div id="content">
<% using (Html.BeginForm()) { %>
Enter the Post Title: <%= Html.TextBox("Title", Model.Title, 50) %><br />
Enter the Post Body: <%= Html.TextArea("Body", Model.Body) %><br />
<%= Html.SubmitButton() %>
<% } %>
</div>
You can take it a step further and display the errors as well in the view, directly from the ModelState that you set in the controller.
<div id="content">
<%= Html.ValidationSummary() %>
<% using (Html.BeginForm()) { %>
Enter the Post Title:
<%= Html.TextBox("Title", Model.Title, 50) %>
<%= Html.ValidationMessage("Title") %><br />
Enter the Post Body:
<%= Html.TextArea("Body", Model.Body) %>
<%= Html.ValidationMessage("Body") %><br />
<%= Html.SubmitButton() %>
<% } %>
</div>
What is interesting with this approach is that you will notice I am not setting the validation summary, nor the individual validation messages in the View. I like to practice DDD concepts, which means my validation messages (and summaries) are controlled in my domain and get passed up in the form of a collection. Then, I loop throught he collection (if any errors exist) and add them to the current ModelState.AddErrors collection. The rest is automatic when you return View(post).
Lots of lots of convention is out. A few books I highly recommend that cover these patterns in much more detail are:
Professional ASP.NET MVC 1.0
Pro ASP.NET MVC 1.0 Framework
And in that order the first covers the raw nuts and bolts of the entire MVC framework. The latter covers advanced techniques outside of the Microsoft official relm, with several external tools to make your life much easier (Castle Windsor, Moq, etc).
The View is supposed to be dumb in the MVC pattern, just displaying what the Controller gives it (obviously we do often end up with some logic there but the premise is for it not to be) as a result, controls aren't responsible for their state, it'll come from the controller every time.
I can't recommend Steven Sanderson's book Pro ASP.NET MVC by Apress enough for getting to grips with this pattern and this implementation of it.
In Web Forms, control values are maintained in the viewstate so you (theoretically) don't need to reinitialize and such with each postback. The values are (again theoretically) maintained by the framework.
In ASP.NET MVC, if you follow the paradigm, you don't need to maintain state on form elements. The form element values are available on post where your controller can act on them (validation, database updates, etc.). For any form elements that are displayed once the post is processed, you (the developer) are responsible for initializing them - the framework doesn't automatically do that for you.
That said, I have read about a mechanism called TempData that allows your controller to pass data to another controller following a redirect. It is actually a session variable (or cookie if you configure it as such) but it is automatically cleaned up after the next request.
The answer really depends on the types of controls you are trying to maintain state for. For basic Html controls then it is very easy to maintain state with your Models, to do this you need to create a strongly typed view.
So if we had a User model with the properties: Username, FullName, Email, we can do the following in the view:
<%= Html.ValidationSummary() %>
<% using (Html.BeginForm()) { %>
<fieldset>
<legend>User details</legend>
<%= Html.AntiForgeryToken() %>
<p>
<label for="Username">Username:</label>
<%= Html.Textbox("Username", Model.Username, "*") %>
</p>
<p>
<label for="FullName">FullName:</label>
<%= Html.Textbox("FullName", Model.FullName, "*") %>
</p>
<p>
<label for="Email">Email:</label>
<%= Html.Textbox("Email", Model.Email, "*") %>
</p>
<p>
<input type+"submit" value="Save user" />
</p>
</fieldset>
<% } %>
We would then have two controller actions that display this view, one for get and another for post:
[AcceptVerbs(HttpVerbs.Get)]
public ActionResult User()
{
return View(new User())
}
[AcceptVerbs(HttpVerbs.Post)]
[ValidateAntiForgeryToken]
public ActionResult User([Bind(Include = "Username,FullName,Email")]User user)
{
if (!ModelState.IsValid()) return View(user);
try
{
user.save()
// return the view again or redirect the user to another page
}
catch(Exception e)
{
ViewData["Message"] = e.Message;
return View(user)
}
}
Is this what you are looking for? Or do you want to maintain the state of Models that are not being displayed in a form between requests?
The key thing to remember is that your code executes on the server for the duration of the request and ends, the only information you can pass between your requests is basic html form data, url parameters and session information.
As other people have mentioned, I'd highly recommend Steve Sandersan's Pro ASP.NET MVC Framework for a complete understanding of working with the MVC Framework.
hidden fields, like:
<% using (Html.BeginForm<SomeController>(c=>c.SomeAction(null))) {%>
<%= Html.Hidden("SomeField", Model.SomeField)%>
<%= Html.Hidden("AnotherField", Model.AnotherField)%>
setting the specific model & not having any explicit fields (gives u hidden fields). In the example below, the Model is filled by the controller with values received from the last post, so this enables a no js option in the page that can filter based on a status:
Some Filter: <% using( Html.BeginForm<SomeController>(
c => c.SomeAction(model.SomeField, model.AnotherField, model.YetAnotherField, null, model.SomeOtherField)
)) { %>
<%= Html.DropDownList("status", Model.StatusSelectList)%>
<input type="submit" value="Filter" class="button" />
<% } %>
use extension methods to create fields, if u just want the fields to be filled with posted values when u are showing failed validation messages on the submitted form
on asp.net mvc 2 they introduced a way to save an instance in a hidden field ... encoded + (I think) signed
TempData if everything of the above doesn't do it (goes through session - cleaned on the next request)
as u mentioned, when using ajax the state is already in the previously loaded fields in the client site. If u l8r on need to do a full post, update any field u might need to with your js.
The above are all different independent options to achieve it that can be used in different scenarios. There are more options I didn't mention i.e. cookies, session, store stuff in db (like for a resumable multi step wizard), parameters passed to an action. There is no 1 single mechanism to rule them all, and there shouldn't be.
The best way to do this, i think, is to serialize your original model to a hidden field, then deserialize it and update the model on post. This is somewhat similair to the viewstate approach, only you have to implement it yourself. I use this:
first i need some methods that make things easier:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Web.Mvc;
using LuvDaSun.Extensions;
using System.Web.UI;
namespace LuvDaSun.Web.Mvc
{
public static class HtmlHelperExtensions
{
static LosFormatter _losFormatter = new LosFormatter();
public static string Serialize(this HtmlHelper helper, object objectInstance)
{
var sb = new StringBuilder();
using (var writer = new System.IO.StringWriter(sb))
{
_losFormatter.Serialize(writer, objectInstance);
}
return sb.ToString();
}
}
[AttributeUsage(AttributeTargets.Parameter)]
public class DeserializeAttribute : CustomModelBinderAttribute
{
public override IModelBinder GetBinder()
{
return new DeserializeModelBinder();
}
}
public class DeserializeModelBinder : IModelBinder
{
static LosFormatter _losFormatter = new LosFormatter();
public object BindModel(ControllerContext controllerContext, ModelBindingContext bindingContext)
{
if (bindingContext.ModelType.IsArray)
{
var type = bindingContext.ModelType.GetElementType();
var serializedObjects = (string[])bindingContext.ValueProvider.GetValue(bindingContext.ModelName).ConvertTo(typeof(string[]));
var deserializedObjects = Array.CreateInstance(bindingContext.ModelType.GetElementType(), serializedObjects.Length);
for (var index = 0; index < serializedObjects.Length; index++)
{
var serializedObject = serializedObjects[index];
var deserializedObject = _losFormatter.Deserialize(serializedObject);
deserializedObjects.SetValue(deserializedObject, index);
}
return deserializedObjects;
}
else
{
var serializedObject = (string)bindingContext.ValueProvider.GetValue(bindingContext.ModelName).ConvertTo(typeof(string));
var deserializedObject = _losFormatter.Deserialize(serializedObject);
return deserializedObject;
}
}
}
}
then in my controller i have something like this (to update a product)
public ActionResult Update(string productKey)
{
var model = _shopping.RetrieveProduct(productKey);
return View(model);
}
[AcceptVerbs(HttpVerbs.Post)]
public ActionResult Update([Deserialize]Shopping.IProduct _model, FormCollection collection)
{
UpdateModel(model);
model.Save();
return RedirectAfterPost();
}
and i need a hidden field that holds the serialized object in the form:
<%
using (Html.BeginRouteForm("Product", FormMethod.Post, new { id = UniqueID, }))
{
%>
<%= Html.Hidden("Model", Html.Serialize(Model)) %>
<h1>
Product bewerken</h1>
<p>
<label for="<%=UniqueID %>_Name">
Naam:</label>
<input id="<%=UniqueID %>_Name" name="Name" type="text" value="<%= Html.AttributeEncode(Model.Name) %>"
class="required" />
<br />
</p>
<p>
Omschrijving:<br />
<textarea id="<%= UniqueID %>_Description" name="Description" cols="40" rows="8"><%= Html.Encode(Model.Description) %></textarea>
<br />
</p>
<p>
<label for="<%=UniqueID %>_Price">
Prijs:</label>
<input id="<%= UniqueID %>_Price" name="Price" type="text" value="<%= Model.Price.ToString("0.00") %>"
class="required" />
<br />
</p>
<ul class="Commands">
<li>Annuleren</li>
<li>
<input type="submit" value="Opslaan" /></li>
</ul>
<%
}
%>
<script type="text/javascript">
jQuery('#<%= UniqueID %>').validate();
</script>
as you can see, a hidden field (Model) is added to the form. It contains the serialization information for the original object. When the form is posted, the hidden field is also posted (ofcourse) and the contents are deserialized by the custom modelbinder to the original object which is then updated and saved by the controller.
Do note that the object you are serializing needs to be decorated with the Serializable attribute or needs to have a TypeConverter that can convert the object to a string.
The LosFormatter (Limited Object Serialization) is used by the viewstate in webforms. It also offers encryptionn of the serialization data.
greets...
AJAX calls is what we do. If you're talking about grids in general, check out JQGrid and how they recommend the AJAX implementation.
I have a partial view in MVC that goes something like:
<div id="comments">
...
</div>
Inside that div there's a form that calls a controller using AJAX and gets back that same partial view. The problem is that the results of calling the view replaces the contents of the div, not the whole div, and I end up with:
<div id="comments">
<div id="comments">
...
</div>
</div>
The only solution I can think about with my week of experience in ASP.Net MVC and AJAX is to put the div outside the partial view and make the partial view only contain the inside part, but then the form would refer to an id outside the view where the form is located breaking the little encapsulation I have left there. Is there any better solution?
The unobtrusive Ajax library that ships with .NET MVC 3 uses callbacks that are based on the four callbacks from jQuery.ajax. However, the InsertionMode = InsertionMode.Replace from the Ajax.BeginForm method does not result in jQuery's replaceWith being called. Instead, .html(data) is used to replace the contents of the target element (and not the element itself).
I have described a solution to this problem on my blog:
http://buildingwebapps.blogspot.com/2011/11/jquerys-replacewith-and-using-it-to.html
Are you using an AjaxHelper.Form or jQuery. If you are using jQuery, have you tried using replaceWith()? Using AjaxHelper are you using AjaxOptions { InsertionMode = InsertionMode.Replace }? I would think that using either you would be able to replace the entire DIV with the results from the partial view.
Using
AjaxOptions { UpdateTargetId = "myDiv", InsertionMode = InsertionMode.Replace }
should replace the whole content of '#myDiv' element, as tvanfosson says. Your problem is where is '#myDiv' located. Here's an example:
<div id="myDiv">
<% Html.RenderPartial("MyPartialView"); %>
</div>
where MyPartialView is:
<div id="comments">
<% using (Ajax.BeginForm(new AjaxOptions() { UpdateTargetId = "myDiv", InsertionMode = InsertionMode.Replace } )) {%>
...
<input type="submit" value="Submit comment" />
<% } %>
</div>
If you include '#myDiv' div inside the partial view, it will be rendered right after receiving the response (together with its content), and then it's content will be replace with the response which is the same partial view (including its own '#myDiv' div), and that's why you always end up with 2 nested divs.
You should always use a container for your partial views and then set the UpdateTargetId to the container id.
Edit: I updated the code to represent the exact situation you describe in your question.
I had this same problem in Asp.Net MVC 5.
I did not want the PartialView to have some knowledge about what div it might be contained within, so I did not accept that work around.
Then, I noticed the other answers referring to ReplaceWith and found the simple solution:
InsertionMode = InsertionMode.ReplaceWith
Now, the mvc partial view can completely replace itself with the ajax helpers without having any dependencies on names outside itself.
Your should try with jQuery too (from my answer on MS MVC form AJAXifying techniques):
<script type="text/javascript">
$(document).ready(function() {
ajaxify($('div#comments'));
});
function ajaxify(divWithForm) {
var form = $('form', divWithForm);
$(':submit', form).click(function (event) {
event.preventDefault();
$.post(form.attr('action'), form.serialize(),
function(data, status) {
if(status == 'success') {
var newDivWithForm = $(data);
ajaxify(newDivWithForm);
divWithForm.after(newDivWithForm).remove();
}
}
);
});
}
</script>
Did you solved the problem? I had the same issue but I found this:
http://buildingwebapps.blogspot.ro/2011/11/jquerys-replacewith-and-using-it-to.html
I hope it helps you.