MVC4 Ajax forms: How to display server side validation - asp.net

I am using #Ajax.BeginForm helper method, which submits form data to the server by Ajax. When the data arrive to the server, some server side validation is processed and final result is passed back to the browser.
My problem is, I want the errors to be displayed without page refresh. I have found plenty of questions based on this but they are old. I am wondering if there is some new way how to achieve this. The best way I have found so far is to process the result using jQuery. But maybe in new MVC4 there is some built in functionality how to achieve this problem in a better way?

Your view should look similar to this:
<div id="update-this">
#using (Ajax.BeginForm("YourAction", new AjaxOptions { UpdateTargetId = 'update-this' }))
{
}
</div>
Also use #Html.ValidationMessageFor(model => model.someField) next to your fields to display the error message.
On server side return a partial view if there was any error:
public ActionResult YourAction(YourModel yourmodel)
{
if (ModelState.IsValid)
{
// Do what is needed if the data is valid and return something
}
return PartialView("DisplayPartial", yourmodel);
}
And use Data Annotations on your model to make it work. (Tutorial here.)

Related

asp.net mvc - ajax form (Ajax.beginform) in partial view redirects to show json response when the partial view is rendered via ajax

I have a partial view with an ajax form
#using (Ajax.BeginForm("SaveSettings", "Config", new AjaxOptions
{
HttpMethod = "Post",
OnSuccess="settingsUpdateSucces"
}, new { enctype = "multipart/form-data", id = "SaveSettings" }))
{
#Html.HiddenFor(m => m.Id)
//other fields go here
<button id="btnSaveSettings" type="submit" >Save Settings</button>
}
This partial view and the form works in one scenario but not the other.
Let me explain both scenarios
Scenario 1:
The partial page is rendered using "Html.Partial" in an asp.net page
relevant parts of the page
#{
ViewBag.Title = "Edit";
Layout = "~/Layout/V1.cshtml";
}
<!--other non-relevant markup and code here-->
<div>
<h3>Settings</h3>
#Html.Partial("_Settings")
</div>
In this scenario the ajax form works without any problems and the page is not redirected.
This code has been running for over 6 months and no issues whatsoever.
Scenario 2
Now, I am trying to get the same partial to work on another new page.
This is a new page - which works like a wizard.
So, in one of the steps a partial page is added (using Html.Partial). This page has a dropdown, when selected, another partial page is rendered via ajax.
One of the selection loads the above mentioned "_Settings" partial page using this code
function loadPartial(id) {
$.get('/Config/_Settings?sid=' + id, function (data) {
$('#partialSettingsPlaceHolder').html(data);
});
}
The partial page and form is loaded fine, but when I submit a redirect happens and the JSON returned by the ajax form is shown.
I am unable to understand why this is happening in scenario 2.
PS:
I already searched for similar issues and the answers mention that this happens when the required js files - jquery, "jquery.validate.unobtrusive.min.js", "jquery.unobtrusive-ajax.js" - are not referenced and downloaded.
Please note that in both scenarios, jquery, "jquery.validate.unobtrusive.min.js", "jquery.unobtrusive-ajax.js" are referenced and downloaded in the main page - ie the page containing the partial page.
I think your issue could caused by submitting handler function for ajax form only binding at page loaded or document ready event of page which contain ajax form. Since your partial page is adding dynamic via ajax, so the dynamic added ajax form will be full submitted as a normal form.
You could try below work-around solution.
Manually adding submitting event handler function for newly added form, then inside this handler function, we do submitting via ajax instead of full submit.
function loadPartial(id) {
$.get('/Config/_Settings?sid=' + id, function (data) {
var placeholder = $('#partialSettingsPlaceHolder');
placeholder.html(data);
$('form', placeholder).on('submit', submitHandler);
});
}
function submitHandler(event) {
event.preventDefault();
event.stopImmediatePropagation();
// validation code here depend on validation plugin you are using, for example:
// if (!$(this).valid()) return false;
$.ajax({
url: this.action,
type: this.method,
data: $(this).serialize()
}).done(function (data) {
// your code in case of success
}).fail(function (jqXHR, textStatus) {
// your code in case of fail
});
return false;
}
Of course, this is just a work-around solution. If you want to do it in more formal way, I suggest you to study auto generated source code for ajax form and aspx page (for example using Developer Tool of browsers).
The reason why your second scenario is not working is that you are loading and adding your form dynamically to our page after the initial page load.
if you will take a look on jquery unobtrusive ajax code you will find that section which is doing few calls like $(document).on(...). That is basically adding listeners directly to html elements like form or input right after page is ready. But because of that those click events are not being attached to elements which will be appended to page later. Unfortunarelly I cannot see in that script any possibility to reinitialise it. So maybe your only option might be to create script which can be called after adding your form and will do the same steps as the original version. That way ajax behaviour should remain the same.
Another option might be to render the form without ajax but hide it with css? That is very dependent on your page styling etc. That way event listeners will get applied and you could then only show the form instead of appending it as a fresh node

ASP.Net - how to have multiple submit buttons and also submit the form via javascript?

I'm new to ASP.Net and am trying to make a web application using MVC2.
On one particular page I need to have multiple submit buttons - after reading up from this post I found this method which worked well in my project.
So I have a few submit buttons handled in my controller like this:
[HttpPost]
[MultiButton(Key = "action", Value = "Button1")]
public ActionResult Action1(MyViewModel myViewModel)
{ //do stuff
return View(newViewModel)
}
[HttpPost]
[MultiButton(Key = "action", Value = "Button2")]
public ActionResult Action2(MyViewModel myViewModel)
My problem is that now I want to also postback my form on various client events. I tried to do this in the view by using javascript in there somewhere.
<% using (Html.BeginForm("Index", "MyController")){ %>
document.forms["form1"].submit();
With a 'normal' action on the controller:
[HttpPost]
public ActionResult Index(MyViewModel myViewModel)
{
}
But when I add this, now the multiple submit buttons do not work properly due to an ambiguous match exception between Action1 and Index. I realise that they have the same signature but as a beginner, I'm a bit stuck at this point!
What can I do to get all the different submit options working together? Please advise and/or point out where I'm going wrong. Thanks

ASP.NET MVC Load page with AJAX

I have this situation:
A page with an accordion with 2 tabs, one has a list of paymentmethods, the second has a summary of the order with orderlines, amounts and totals (rendered as partialview). Selecting a paymentmethod causes the order totals to be recalculated, extra costs etc might apply.
What is the recommended way to display the new ordersummary after a paymentmethod is selected, using AJAX?
Doing an AJAX call and getting all the new amounts, orderlines, etc and setting these values using JS seems inefficient to me. Ideal situation would be if I could make an AJAX call with the selected payement method and this call would return the HTML which I can use to replace the old summary.
Is it bad to render a partialview to HTML on the server and return it using JSON? What is best practice for this situation?
I have an example here:
Javascript
$("#divForPartialView").load("/HelloWorld/GetAwesomePartialView",
{ param1: "hello", param2: 22}, function () {
//do other cool client side stuff
});
Controller Action
public ActionResult GetAwesomePartialView(string param1, int param2)
{
//do some database magic
CustomDTO dto = DAL.GetData(param1, param2);
return PartialView("AwesomePartialView",dto);
}
In your action method return a PartialView([view name]).
Then you can do this with jquery:
var req = $.ajax({
type:"GET",//or "POST" or whatever
url:"[action method url]"
}).success(function(responseData){
$('targetelement').append($(responseData));});
Where 'targetelement' is a selector for the element into which you want to inject the content.
You might want to do $('targetelement').html(''); first before appending the response to the target element.
Update
Or, better yet, use .load from Rick's answer.

ASP.NET MVC 2 - Simple Search Page

I just started ASP.NET MVC (coming from WebForms) and I'm struggling with some really basic concepts.
I want to create a single page that uses a textbox for date input. I would like the date input to be passed to the index of my controller which looks like this:
public ActionResult Index(int month,
int day,
int year){
var visitors = visitorRepoistory.FindVisitorsByDate(month, day, year).ToList();
return View("Index", visitors);
}
Up to this point I have used scaffolding with strongly typed views so everything was kind of glued together for me.
What would/should my view look like? Would I use an actionlink (this is a get request after all, right?) and not a submit button.
Thanks.
I thought about this for a while before trying to come up with an answer. What threw me initially was the concept of turning a single text input string into it's month, day, and year components. In ASP.NET MVC, it would be much easier to just accept the string for the date. This way, your code changes to:
public ActionResult Index(string date) {
try
{
DateTime dtDate = DateTime.Parse(date);
var visitors = visitorRepoistory.FindVisitorsByDate(dtDate.month,
dtDate.day, dtDate.year).ToList();
return View("Index", visitors);
}
catch (FormatException)
{
//String was not a valid date/time
}
}
Are there ways to split it up into 3 ints? I'm sure. But to me, this would be the easiest/quickest way to the goal.
So in the view, you'll have your form looking something like this:
<% using(Html.BeginForm("VisitorSearchController", "Index")) { %>
Enter a date: <%= Html.TextBox("date") %>
<input type='submit' value='Search' />
<% } %>
Where "VisitorSearchController" is the name of the controller you want to post back to. Of course, "Index" is the method you're posting to. I'd stick with the submit button for now unless you're trying to get a LinkButton equivalent on the page. But you can save the "prettying up" part after functionality, right?
Edit: Added view code to the answer.
EDIT after comment:
Simplest way is to make the search input page post (not get) back to some other method, parse the date out, then redirect to the Action you have specified.
If you want to do it through get, then you can use some Javascript trickeration to link to whatever they type in, but I recommend the former.

ASP.NET MVC Submitting Form Using ActionLink

I am trying to use link to submit a form using the following code:
function deleteItem(formId) {
// submit the form
$("#" + formId).submit();
}
Basically I have a grid and it displays a number of items. Each row has a delete button which deletes the item. I then fire the following function to remove the item from the grid.
function onItemDeleted(name) {
$("#" + name).remove();
}
It works fine when I use a submit button but when I use action link the JavaScript from the controller action is returned as string and not executed.
public JavaScriptResult DeleteItem(string name)
{
var isAjaxRequest = Request.IsAjaxRequest();
_stockService.Delete(name);
var script = String.Format("onItemDeleted('{0}')", name);
return JavaScript(script);
}
And here is the HTML code:
<td>
<% using (Ajax.BeginForm("DeleteItem",null, new AjaxOptions() { LoadingElementId = "divLoading", UpdateTargetId = "divDisplay" },new { id="form_"+stock.Name }))
{ %>
<%=Html.Hidden("name", stock.Name)%>
<a id="link_delete" href="#" onclick="deleteItem('form_ABC')">Delete</a>
<% } %>
</td>
My theory is that submit button does alter the response while the action link simply returns whatever is returned from the controller's action. This means when using submit the JavaScript is added to the response and then executed while in case of action link it is simply returned as string.
If that is the case how can someone use action links instead of submit buttons.
UPDATE:
Seems like I need to perform something extra to make the action link to work since it does not fire the onsubmit event.
http://www.devproconnections.com/article/aspnet22/posting-forms-the-ajax-way-in-asp-net-mvc.aspx
My guess is the MS Ajax form knows how to handle a JavaScriptResponse and execute the code whereas your plain old Action link, with no relationship to the AjaxForm, does not. I'm pretty sure the MS ajax library essentially eval()s the response when it sees the content type of javascript being sent back.
Since you have no callback in your deleteItem() method there is no place for the script to go. To fix you'll have to manually eval() the string sent back which is considered a bad practice.
Now I'm not familiar with the MS Ajax library to be certain of any of this but what your doing is possible. I'd do things differently but don't want to answer with a "my way is better" approach ( especially because your blog has helped me before ) but I'd like to show this can be easier.
I'd ditch the form entirely and use unobtrusive javascript to get the behavior you want. IN psuedo jqueryish ( don't know ms ajax ) code:
function bindMyGrid() {
$('.myDeleteLink').onclicksyntax( function() {
//find the td in the row which contains the name and get the text
var nameTdCell = this.findThisCellSibling();
//do an ajax request to your controller
ajax('myUrl/' + nameTdCell.text(), function onSuccessCallback() {
//get the tr row of the name cell and remove it
nameTdCell.parent().remove();
});
});
}
This also gains the benefit of not returning javascript from your controller which some consider breaking the MVC pattern and seperation of concerns. Hope my psuedo code helps.
Try without the UpdateTargetId property in the AjaxOptions (don't specify it)
new AjaxOptions() { LoadingElementId = "divLoading" }
What about just change look of a standard or using some css class? It'll look like a link and you'll avoid some problems you get with anchors - user will be able to click on it by a mouse wheel and open that link in a new tab/window.

Resources