Updating result from ajax calls in partial views in asp.net mvc2 - ajax

I have a ASP.Net MVC 2 partial view like the one below,
FORM 1:
<div id="d1">
<% using (Ajax.BeginForm("ManageSources", "Sources",
saveAjaxOptions))
{ %>
... all this form's html markup goes here
<div id="src_Parameters"></div>
<% } %>
</div>
Form 2
<% using (Ajax.BeginForm("FetchParameters", "Sources",
fetchAjaxOptions))
{ %>
hidden fields to send values to the action method go here
.. button to post this form
<% } %>
Now, in the fetchAjaxOptions, i have given the target div to be src_Parameters, which resides inside the form1, when i post the second form, i am being returned a partial view as the only view page, instead of populating the results in the src_Parameters div.
How do i accomplish this. Actually the results of the FetchParameters ajax call should be able to be posted for the ManageSources ajax call.
Where is the problem or will nesting the forms workout since this is using ajax forms.. Kindly suggest me the right procedure to do this task.

You haven't posted your server side code, but I suspect you have forgotten to have set the return type to be a partial view.
public PartialViewResult FetchParameters()
{
//do some stuff
return PartialView(“_ViewName”, viewModel)
}
It could also be that you fotgot to add a reference to the Microsoft Ajax
<script src="../../Scripts/MicrosoftMvcAjax.js" type="text/javascript"></script>

Related

OutputCache for partialView not working?

Hi,
I have a ASP.NET MVC 3 website where I have created a action that returns a partial view. This view have the following :
<%# OutputCache Duration="10000" VaryByParam="none" %>
And to render this from my main view I use this :
<% Html.RenderAction("ImageWall", "Image"); %>
The problem is that it is not caching at all? When setting a breakpoint I can see that the expensive drawing is running everytime?
For this, Use Action Attribute
<OutputCache(Duration:=10000, VaryByParam:="any")>
Function ImageWall() As PartialViewResult
Return PartialView()
End Function
For Vb.Net sample, sorry

MVC 3 Razor #Html.ValidationMessageFor not working in partial loaded via jquery.load()

I have put together a small example here just to replicate the problem.
I have a strongly typed partial view _Name.cshtml:
#model ValidationInPartial.ViewModels.MyViewModel
<h2>#ViewBag.Message</h2>
<fieldset>
<legend>Name</legend>
<div class="editor-label">
#Html.LabelFor(model => model.MyName)
</div>
<div class="editor-field">
#Html.EditorFor(model => model.MyName)
#Html.ValidationMessageFor(model => model.MyName)
</div>
Reload Name
<p>
<input type="submit" value="Create" />
</p>
</fieldset>
<script type="text/javascript">
$(document).ready(function () {
$("#reload").click(function () {
$("#divName").load("Home/NameReload");
});
});
</script>
that is initially loaded and displayed inside the main Index.cshtml
<div id="divForm">
#using (Html.BeginForm()) {
<div id="divName">
#Html.Partial("_Name")
</div>
}
</div>
The field MyName is required and validation is implemented through Required attribute in MyViewModel
namespace ValidationInPartial.ViewModels
{
public class MyViewModel
{
[Required(ErrorMessage = "Please enter a Name.")]
public string MyName { get; set; }
}
}
After the page is loaded the first time, if you click the Create button leaving the field empty the validation message "Please enter a Name." shows beside the field and the field itself turns pink, which is the expected behaviour.
Now by clicking the "Reload Name" link, which makes an ajax call (jquery.load(...)), the partial is reloaded, here is controller code:
public PartialViewResult NameReload()
{
MyViewModel myViewModel = new MyViewModel();
ViewBag.Message = "Name Reloaded";
return PartialView("_Name", myViewModel);
}
This time if you click the Create button leaving the field empty the validation message does not appear beside the field, although the field turns pink.
It turns out that when reloading the partial the #Html.ValidationMessageFor doesn't render the validation message as the first time.
Here is the jquery files I use
<script src="#Url.Content("~/Scripts/jquery-1.5.1.min.js")" type="text/javascript"></script>
<script src="#Url.Content("~/Scripts/jquery.validate.js")" type="text/javascript"></script>
<script src="#Url.Content("~/Scripts/jquery.validate.unobtrusive.min.js")" type="text/javascript"></script>
<script src="#Url.Content("~/Scripts/jquery.unobtrusive-ajax.min.js")" type="text/javascript"></script>
I wonder if this is a bug in the way the Razor engine renders the #Html.ValidationMessageFor or is that a problem with jquery?
Any idea why this happens?
I have also read somewhere that the ajax call looses all the scripts for the page, in fact I have to keep any javascript code inside the partial so that they can be rendered and used again.
In the meantime I found a workaround which is to manually render in the partial what was supposed to be rendered by #Html.ValidationMessageFor which is:
<span class="field-validation-valid" data-valmsg-replace="true" data-valmsg-for="MyName"></span>
However this workaround means that if we change the type of validation or just the validation message inside the Required attribute in the ViewModel, we need to modify this hard-coded piece of html in the view.
#NickBork has a great answer here. The key is that ASP.NET's MVC rendering engine does not output the validation script if it doesn't think that there is a form. The example given hacks it buy putting in a form and then selection an inner section of HTML from was was returned, essentially throwing the outer wrapper of the form away.
There is another method so that you can just get your view:
ViewContext.FormContext = new FormContext();
With this method, there won't actually be FORM code output, but the validation markup will be there.
Thanks,
John
Validation markup (span tags, custom field attributes, etc) are not rendered unless your fields are contained within a FORM. The validation plugin itself does not work with elements outside of a form.
When ASP.NET renders your Partial View the controls are not within a form and thus do not get the elements rendered.
When you load you're partial content you'll need to parse the HTML using a jQuery selector.
In my sample below I have a TBODY on the parent View page that contains rows. When I need to add additional rows, I make a call to a View which had a form, table, tbody and collection of rows.
$.ajax({
type: "POST",
url: "/controller/action",
data: ({Your: 'dataHere'}),
dataType: "html",
success:
function(response){
$('tbody').append($('tbody',$(response)).html());
//The validation plugin can't bind to the same form twice.
//We need to remove existing validators
$('form').removeData("validator");
//Refresh the validators
$.validator.unobtrusive.parse(document);
},
error:
function(){
alert('An error occured while attempting to add the new content');
}
});
Note that I'm using a jQuery selector to select the rows that are inside of the View/PartialView that are loaded in by using AJAX:
$('tbody',$(response)).html()
The rest of the wrapper just appends the rows from the AJAX View/PartialView to the calling parents tbody:
$('tbody').append($('tbody',$(response)).html());
A couple other notes, after the validator plugin has been run on a form, it can not be called again without re-adding it (see jquery.validate.unobtrusive not working with dynamic injected elements)
To fix this, I first call the following method to remove all validators:
$('form').removeData("validator");
$("form").removeData("unobtrusiveValidation");
I then refresh the validators using the following:
$.validator.unobtrusive.parse(document);
I can't remember where I found the solution. The reason is because you are loading a PartialView into a View that has already been parsed by the jquery.validator.unobtrusive library. You need to re-parse the unobtrusive library
function ReparseValidation(){
jQuery.validator.unobtrusive.parse("#yourcontainer");
}

Razor Partial View not Rendering

If I use the following Controller method:
public ActionResult Menu()
{
// do stuff...
return PartialView("viewName", navLinks);
}
calling the partial view in _Layout.cshtml like this:
<div id="categories">
#{ Html.Action("Menu", "Nav"); }
</div>
With the following ASCX partial view:
<%# Control Language="C#"
Inherits="ViewUserController<IEnumerable<MyDataType>>" %>
<% foreach(var link in Model) { %>
<%: Html.Route.Link(link.Text, link.RouteValues) %>
<% } %>
everything works fine. Yay.
BUT, if I use either of the following RAZOR partial views:
#model IEnumerable<MyDataType>
#foreach(var link in Model){
Html.RouteLink(link.Text, link.RouteValues);
}
or...
#model IEnumerable<MyDataType>
#{
Layout = null;
}
#foreach(var link in Model){
Html.RouteLink(link.Text, link.RouteValues);
}
I get nothing. there's no exception thrown, I just don't get anything rendered. I know the problem isn't with the controller method (it works just great with the ASCX partial view).
What's going on here?
Try changing this:
#foreach(var link in Model){
Html.RouteLink(link.Text, link.RouteValues);
}
to this:
#foreach(var link in Model){
#Html.RouteLink(link.Text, link.RouteValues);
}
It looks like without the # the method is being called, but the return value is just being dscarded. Putting the # causes it to be written in the response.
The RenderAction method writes the action directly to the view and returns void.
The Action method returns the action's contents but doesn't write anything to the view.
Writing #something will print the value of something to the page.
You cannot write #Html.RenderAction, since RenderAction doesn't return anything.
Writing Html.Action(...) (without #) calls the method normally, but doesn't do anything with its return value.
OK, Changing the way the it was called from _Layout.cshtml worked...
<div id="categories">
#Html.Action("Menu", "Nav");
</div>
It is important to note, that #Html.RenderAction DOES NOT work for me. I'd really love some explanation here, because right now, learning Razor is frustrating me as there is little documentation, and problems like these which should take minutes to resolve, are eating up way too much of my time.

ASP.NET MVC 2 server-side validation for ajax form

I've faced the following problem. I'm developing a form for the site and this form should have validation. I wanna to use native ASP.NET MVC 2 validation functionality but get stubborn with it. I have a form that is loaded via $.get and displayed using jQuery UI modal dialog. All examples I found explains how to use MVC validation with simple forms and avoid Ajax forms.
I can enable client side validation for this form, but I need to handle server-side validation correctly. How can I handle server-side validation model errors for ajax forms?
When you pass your object back to the controller, you have to wrap your code in If ModelState.IsValid
Below is a simplified version of how I edit a user. The first "EDIT" sends the User object TO the View. The second "EDIT" handles the post from the view.
Function Edit() As ActionResult
''# do stuff to populate your User
Return View(User)
End Function
<AcceptVerbs(HttpVerbs.Post)> _
Function Edit(ByVal user as User)
If ModelState.IsValid Then
''# do your valid stuff
Else
''# The posted form was not valid, send the user back
Return View(user)
End If
End Function
Here's the same thing in C#
public ActionResult Edit()
{
// do stuff to populate your User
return View(User);
}
[AcceptVerbs(HttpVerbs.Post)]
public object Edit(User user)
{
if (ModelState.IsValid) {
// do your valid stuff
} else {
//'# The posted form was not valid, send the user back
return View(user);
}
}
EDIT:
On your view, if you want to add AJAX validation, just add the following.
<%
Html.EnableClientValidation() ''# This is where all the magic happens. It will build your clientside validation for you out of your MetaData.
Using Html.BeginForm("Edit", "Users")
%>
<!-- all your markup crap -->
<tr>
<td>
<%: Html.LabelFor(Function(model) model.UserName)%></td>
<td>
<%: Html.TextBoxFor(Function(model) model.UserName) %>
<%: Html.ValidationMessage("UserName", "*")%><br />
</td>
</tr>
<!-- somewhere you'll want to add a Validation Summary of all your errors -->
<%= Html.ValidationSummary("Oops!, please correct the errors...") %>
<% End Using%>
<!-- bottom of the page -->
<script src="../../Assets/Scripts/MicrosoftAjax.js" type="text/javascript"></script>
<script src="../../Assets/Scripts/MicrosoftMvcAjax.js" type="text/javascript"></script>
<script src="../../Assets/Scripts/MicrosoftMvcValidation.js" type="text/javascript"></script>
EDIT:
Here is some info on rendering using Ajax.BeginForm
http://singulartechnologies.com/asp-net-mvc-ajax-beginform-sample-code
http://msdn.microsoft.com/en-us/library/dd381533.aspx
http://weblogs.asp.net/mikebosch/archive/2008/02/15/asp-net-mvc-submitting-ajax-form-with-jquery.aspx

MVC Transfer Data Between Views

I just started to learn MVC and am trying to understand how it works.
I don't want to send users to different views for all edit, insert and list operations.
In my sample application a View contains a list of items and below the list there is a form (for inserting new items) with action "{Controller}/Create" but there is no Create View.
When a user inserts a new item it posts to the Create action with httpverb post and creates the item and returns back to the List action with RedirectToAction method.
But I can not show any message(error, information etc) to the user in this style because I can not pass data between Create action and List action. How can I do that?
You need to use Post Redirect Get PRG pattern.
Please read this Use PRG Pattern for Data Modification section in this blog post by Kazi Manzur Rashid.
http://weblogs.asp.net/rashid/archive/2009/04/01/asp-net-mvc-best-practices-part-1.aspx
This approach uses TempData to maintain ModelState data between redirects.
[HttpPost, ValidateAntiForgeryToken, ExportModelStateToTempData]
public ActionResult Create(FormCollection form)
{
Product p = new Product();
if (TryUpdateModel<IProductModel>(p))
{
productRepository.CreateProduct( p );
}
else
{
// add additional validation messages as needed
ModelState.AddModelError("_generic", "Error Msg");
}
return RedirectToAction("Index");
}
And here is your Index action method.
[ImportModelStateFromTempData]
public ActionResult Index()
{
IList<Product> products = productRepository.GetAll();
return View("Index", products);
}
And here is your Index view.
<%# Page Language="C#" MasterPageFile="~/Views/Shared/Site.Master" Inherits="System.Web.Mvc.ViewPage<IList<Product>>" %>
<asp:Content ID="Content1" ContentPlaceHolderID="TitleContent" runat="server">
Index
</asp:Content>
<asp:Content ID="Content2" ContentPlaceHolderID="MainContent" runat="server">
<h2>Products</h2>
<% foreach (var p in Model) { %>
<div><%= Html.Encode( p.ProductName ) %></div>
<% } %>
<%= Html.ValidationSummary("Please correct the errors", new { id = "valSumCreateForm" }) %>
<% using (Html.BeginForm("Create", "Product")) { %>
Product Name: <%= Html.TextBox("ProductName") %>
<%= Html.AntiForgeryToken() %>
<% ViewContext.FormContext.ValidationSummaryId = "valSumCreateForm"; %>
<% } %>
</asp:Content>
The ImportModelStateFromTempData
and ExportModelStateToTempData
attributes helps transfer model
state errors between redirects. This
<% ViewContext.FormContext.ValidationSummaryId = "valSumCreateForm"; %> associates the MVC Form with its corresponding Validation Summary.
You can check another answer by me on this here as well.
ViewModel with SelectList binding in ASP.NET MVC2
Let me know if you have any question.
-Soe
Most MVC frameworks have the ability to temporarily store a small bit of data just through the next request, for just this purpose. In ASP.NET MVC its called TempData, in Rails it's called :flash, etc.
This article explains how to use TempData:
One of the more annoying things to
deal with in Web programming is errors
on a form. More specifically, you want
to display error messages, but you
want to keep the previously entered
data. We've all had the experience of
making a mistake on a form that has 35
fields, only to be presented with a
bunch of error messages and a new,
blank form. The MVC Framework offers TempData as a place to store the previously entered information so that the form can be repopulated. This is
something that ViewState actually made
very easy in Web Forms, since saving
the contents of controls was pretty
much automatic. ... TempData is a dictionary,
much like the untyped ViewData.
However, the contents of TempData only
live for a single request and then
they're deleted.

Resources