Post form field values on event change to ActionResult - jquery-post

I have a MVC view that has many fields, input, checkboxes, select lists etc.
When the user makes a choice in any field I use jQuery to trigger a change event that picks the values in all fields and make a (ajax) post to a ActionResult method (with all the values) which makes a database query and at last a search result is returned.
The values from the html fields are put back into the fields so that the user may continue narrowing down his search.
I find it very error-prone and cumbersome to use JQuery for this. I have taken a look at Angular and React, but these seems bloated if I only need it for above task.
I'm open towards frameworks, nuget packages, programming languages, as long as it fits well with above explanation.
Thanks

This doesn't quite feel right as an approach- if you are posting to .NET with AJAX, why not post to a WEBAPI controller, and get back a Json results set - deal with everything in JavaScript (jQuery). However, I'd still keep the form element wrapper and use that to post to the ActionResult MVC controller method to return a View for no-JS scenarios.

Related

Returning custom data along with actionresult from an action method

I am sure many people have had this question but I failed to get any results after searching the web and SO or the search keywords were different.
I am working on a new asp.net mvc web app where I get a plain template returned by the index action method on the controller. Later in the document.ready event handler I build the ui dynamically and append the dom elements to the blank template and this just works fine. My issue is I need 2 server calls here,
1) to get the view from the index action method
2) an ajax call inside the document.ready{} to get the data using which I build the ui.
I was wondering if there is any method using which I could pass back the data from the index action method along with the blank template view and use this data to create the ui inside the document.ready event handler. This will save that one additional hit to the server.
The reason for not using partial views is
1) we have some functionality already developed in jquery and
2) in my org people think making the functionality using razor and partial view will not be as flexible, for example building and raising customevent in js is a great feature that helps to keep the functionality loosely coupled from other features. (please correct if we are wrong)
Edit: I thought an example will explain this better,
Say I need to create a list of users, but the entire list and its functionality like checkboxes selection etc are built by a js module. So along with the blank view i want to pass the "users" object which is a class in my models currently.
Kindly suggest.
You have a couple of options:
1) Server-side rendering:
Putting the necessary data into the model would seem to be the obvious thing to do...that's what MVC models are for.
During the building of the HTML your View code runs - so you can access the model values in Razor code, which you can use to build your view and influence the final HTML. So in this scenario you build your view using Razor, rather than constructing it using JS code. You can of course still use JS to change it after the page has loaded, but it would be downloaded into the browser with the HTML already in the desired starting state.
2) Client-side rendering, but with necessary data pre-populated:
If you'd rather stick with your existing client-side rendering code, you could use Razor to inject some ready-made JSON into the JavaScript, so it's effectively hard-coded into the page when it first runs, rather than having to fetch it from the server separately via AJAX.
For example, if you have some object in C# which holds the data, you can serialise it to a JSON string and then use Razor to write that string into your JS in the correct place.

Commonly-accepted approach in MVC for form within jQuery dialog

There seem to be several ways to integrate jQuery dialogs with ASP.NET MVC. Has a specific approach emerged as the commonly-accepted best-practice way to do so?
As an example: I have a list page where clicking "edit" for any of the listed items opens a form in a jQuery dialog, populated with the item's details. User edits details and clicks "save". If the save succeeds on the server-side, the dialog is closed and the list is re-built with fresh data. If the save fails on the server-side, the dialog remains open and displays the error message(s) to the user.
No-JSON approach: each "edit" link is an HREF to an "edit" controller action. That controller action builds a view that is identical to the "list" view, plus it includes a partial action to build the edit form, populate it, and define the javascript to pop it open as a jquery dialog. The "save" is a form-post; if it succeeds, it returns a redirect action back to the list page. If it fails, it rebuilds the entire page (including the form that pops up in a dialog) displaying the error messages as well.
All-JSON approach: the list page renders an empty edit form (hidden), ready to be popped open into a dialog. The "edit" link calls local javascript which does an ajax request to get the full object (I define a controller which returns the full object as a JsonResult). On success, it fills the edit form with the object's data and opens the dialog. The "save" link calls local javascript which bundles the form data into a json object, and calls a post operation with that json object as payload (I define a controller which expects that object, attempts the save, and returns a JsonResult indicating success/failure+errorMessages). Success callback from the ajax request evaluates the returned object, and either shows the error messages in the still-open jquery dialog, or closes the dialog and reloads the "list" page to get fresh data in the list.
[Edit] Ajax-HTML approach: just saw this SO discussion which describes another approach. The "edit" calls local javascript which does an ajax post to get the FULL HTML of the dialog (I would write a controller which returns a partial view: the fully-populated form). It renders the returned HTML into a jquery dialog, and also "re-wires" the form submission to do an ajax-post of the form's contents (I would write an httpPost controller, same as in #2 above). The success callback evaluates the response and populates error messages or closes the dialog.
Some other cool approach I haven't thought of?
Option 1 seems to be more in keeping with "pure" ASP.NET MVC. However, it seems to feature big HTTP payloads (since we're shipping the full page back to the browser on every request), and slower server-side performance (since we're re-building the list on every request).
Option 2 seems to be more consistent with more modern Ajax-based web applications (smaller HTTP payloads, more granular operations). However, it seems like many of the controllers will be JSON controllers, and I'll be writing a lot of client-side code to marshal data from JSON objects to/from form fields, display error messages, etc. It also seems like I'd be missing out on a lot of cool MVC features like EditorFor() and ValidationMessageFor(). It just "feels" like I'm working around the MVC system instead of with it.
[Edit: added option 3] Option 3 seems to be a bit of a hybrid between 1 and 2. I use the "pure" MVC approach to build and populate the form, and return a fully-formed HTML FORM tag. Returning HTML to an ajax request feels weird since it's so verbose, but I can get over it. The post operation is nice, compact JSON which "feels" better over ajax. However, it's unfortunate that the payload object is a FormCollection rather than a real viewmodel object. It seems like I can make use of some of the MVC conveniences (EditorFor()) but not others (ValidationMessageFor()).
I'm looking for the "right" way to do this, not just the fastest way to hack it together. Yeah, yeah, I know there's no universally "right" way. But I'm sure there's some notably wrong ways to do it, and I want to avoid them.
I'm pretty experienced in ASP.NET/C#, but I'm pretty new to MVC. Thanks in advance for your help!
[Edit] - outstanding responses - I wish I could award multiple answers/bounties, as I found several responses extremely useful. But since I can't, I'm marking the top-voted response as the answer. Thanks again to all respondents!
My team and I have a lot of experience writing AJAX enabled MVC apps, and we have used all 3 approaches.
However, my favorite is definitely the AJAX-HTML approach -- Use a PartialView to render the contents of the dialog, which could include server-side validation messages and any other logic.
The biggest benefit of this approach is the separation of concerns - your Views are always responsible for rendering your HTML, and your JavaScript doesn't have to contain any text, markup, or "templates" needed to render the JSON.
Another big advantage is that all the great MVC features are available for rendering the HTML: strongly-typed views, HtmlHelper, DisplayFor and EditorFor templates, DataAnnotations, etc. This makes it easier to be consistent and lends well to refactoring.
Just remember, there's no requirement to stick to a single approach. When your AJAX call only needs something simple, such as a status update like "Success", it's fine to just use a string or JSON to convey those messages. Use PartialViews when HTML is needed, and use simpler methods when communication is needed.
Your 2nd method, the All-JSON approach, seems to be increasingly prevalent with MVC and MVVM client side libraries like Knockout
In this you could actually have all of the data in JSON (including the list) and edit list items (similar to their list item editor demo, just with a dialog rendering isntead of inline, and bind the data to readonly spans in your cells) and then serialize the entirety of the set back to the server on save. Or you could do it with piece-meal saves after each popup edit.
JSFiddle: http://jsfiddle.net/paultyng/weLtH/17/
The JS could be cleaned up a bit, I didn't include a save button, but you should get the idea. The edit dialog could be a single template bound to one edit as well, instead of doing per row, this was just the simplest way to do it with Knockout.
I think the best way would be to render the list normally. Hook up the edit links to go to a separate page (follow me here) like you would normally do.
With JS handle clicking of the link, and do a get to it's href. In the edit action do a check for Request.IsAjaxRequest() and if it is, return a partial view if it isn't, return the full view. Or render the normal edit view without the master page (pass in null to the master page parameter in the View() call or call return Partial()). Take the contents of the result and put it into a dialog.
Also use JS to handle submitting the form and getting the result from the request. If it wasn't successful insert the contents of the view into the dialog to show that there were errors. Otherwise close it and move on.
The benefit to this approach is it's very unobtrusive and still allows functionality for those who don't have JS.
Ok, so your options are pretty much torching the concept of progressive enhancement here. 2 & 3 aren't going to work if your client doesn't support java script. Obviously thats ok if you don't care, but I think I'd try to engineer things so that they degrade gracefully and you are asking for best practise here.
So the way I would construct it, starts with your option 1. You have edit buttons that trigger another action which loads an edit page, and this page is designed with all the validators etc as per normal mvc. That's your base functionality so works with no js.
So then the next question is how do we progressively enhance this to have a nice popup instead of a new page?
Well first step is to create a handler to open your dialog attached to the edit links on click (make sure to e.PreventDefault). Now to save too much coding effort I would be looking to reuse the edit page. This is going to require a bit of refactoring though as you don't want to include the layout for the ajax requests. You can do this a few ways, but I think the cleanest is to have the edit area of the edit view as a partial view which the main edit view uses to render its model.
Then, in your edit action, you can check if you have an ajax request, if so then return a PartialView(mypartialeditview) or a View(editview) if not.
In terms of then submitting the results back to the server if you want an easy life just treat it like a form. You can use the micorsoft unobstrive ajax here and it will be very simple. You use Ajax.BeginForm in your partial view. n.b.This will degrade to a normal form if ajax not available. Have the AjaxOptions for this beginform set to update the div in the dialogue so if it responds with its html you don't have to do anything more, it implies a validation error.
[small aside as you asked above about this: In terms of the HttpPost handler, the default model model binder is amazingly smart, it can bind form fields to properties on a complex class object parameter. This also work with json so you don't have to end up with lots of action methods to support different scenarios.]
So if your update is unsucessful the post handler will return the partial view again, bound to the model so you'll get all your validators. If however the update is successful I would suggest that rather than return anything, the action does a redirect back to your main page which you want to reload anyway as you've changed the underlying.
If you don't like doing a full reload of the main page, then it gets more complex as with the approach above you are returning html. You will either have to jquery over that to find a hidden field or class to indicate success/failure or migrate to a pure json approach which returns a jsonresult. This is getting heavier on the maintenance/coding front though. I'd probably do the jquery check and have it wired to the completion handler of the ajax.Beginform.
If you really want to get your head around this stuff, I have found the Steve Sanderson Pro Asp.net MVC book invaluable. The one I initially read was for MVC2, but just in process of reading the MVC3 update. I have mixed feelings on the update, as its been simplified in a few places - easier to follow now but I feel like a few things are missing, also it was rushed as some errors etc as it gets near the end. I guess maybe they panicked now that MVC4 is being talked about and book wasn't out! Still a good book though and it covers all this stuff beautifully.
Hope this helps. Appreciate it covers some of the same ground as an answer above but hope I've drilled in more for you.
Using jQuery.tmpl() plugin1
I use a similar scenario but do it in a different way.
I have a master list where each item is wrapped in a container (be it table TR or DIV). Some general information about the item is displayed in the master list when there's too much data to contain in a simple list. Hence a master list and not details (of course).
Each item container is usually written this way:
<div class="item" data='<%= item.ToJson() %>'> <!-- single quotes! -->
item visible list data
</div>
The main part here is my custom extension method ToJson() that serializes my item data which can easily be used on the client.
Then I have a jQuery template at the end of a list contained inside a script tag. This template is the actual content of the edit dialog with all item variables set as needed.
Whenever user clicks edit on the item, I simply parse item JSON by:
// in edit link click handler
var itemData = $.parseJSON($(this).closest("[data]").attr("data"));
// display dialog
displayDialog($("#editDialog").tmpl(itemData));
My dialog than takes care of the rest via Ajax calls and closing the dialog when calls are successful or user cancels editing.
This keeps my HTML code to minimum (having only one template) and JSON also contains only those properties that are actually needed.
What to do when your model class has other entity references?
This is quite common that entities are related between each other. Suppose you have a Post and Comment entities:
public class Post
{
public int Id { get; set; }
public string Body { get; set; }
public IList<Comment> Comments { get; set; }
}
Of course you're not interested in related entities when converting your items to JSON on the server. That's why you can put an attribute to related properties so they don't get included in the JSON:
public class Post
{
public int Id { get; set; }
public string Body { get; set; }
[ScriptIgnore]
public IList<Comment> Comments { get; set; }
}
This will make JSON serializer ignore the related property we won't edit in our details editor.
ToJson() extension code
The last thing to put here is extension method code so here it goes:
public static class ObjectExtensions
{
/// <summary>
/// Serializes this object instance to JSON string.
/// </summary>
/// <param name="instance">Object instance being extended.</param>
/// <returns>Returns a JSON string that represents current object instance.</returns>
public static string ToJson(this object instance)
{
JavaScriptSerializer serializer = new JavaScriptSerializer();
// register custom class converters
serializer.RegisterConverters(...);
return serializer.Serialize(instance);
}
/// <summary>
/// Serializes this object instance to JSON string.
/// </summary>
/// <param name="instance">Object instance being extended.</param>
/// <param name="recursionDepth">Serialization recursion limit depth.</param>
/// <returns>Returns a JSON string that represents current object instance.</returns>
public static string ToJson(this object instance, int recursionDepth)
{
JavaScriptSerializer serializer = new JavaScriptSerializer();
// register custom class converters
serializer.RegisterConverters(...);
serializer.RecursionLimit = recursionDepth;
return serializer.Serialize(instance);
}
}
What to do when entities are too complex?
Upper approach is useful when your entities aren't too complex. In cases when:
your entities are complex or have long data (long in terms of serialized string)
determining JSON objects for all items would be too time consuming
unknown JSON object at time of master list display
then you can always send a remote Ajax call to server for a single entity and return either
JSON object to use with dialog template
return partial view with editor
Second approach is better, since converting object instance to either HTML or JSON is practically similar task. but in the second case there's no need for client-side template processing.
But don't use remote requests just because you can. Use an approach that's easier and better for the problem at hand.
1: jQuery template API reference

Critique this strategy

I want to populate a gridview by using jQuery and AJAX. From my calling page jQuery will call a handler (.ashx) that will deliver XML data or HTML markup for the gridview. As I see it I have two choices: 1) deliver XML which is then bound to the design-time gridview on the calling page, or 2) deliver HTML for the gridview. My first question is: which method is easiest?
Now there are two factors which complicate things. First, the gridview must be sortable on all columns. Second, the data will be filtered (some columns will be hidded) by user configuration options which are also to be stored in the database. Knowing this, does your answer to the first question change?
Any comments, insights or gotchas are appreciated.
Dewey
I did something very similar to this on a recent project. I used jqGrid for display purposes - it can easily be bound to JSON-formatted data (and probably XML-formatted data too), and it supports click-column-header-to-sort. I would definitely recommend it for functionality and ease-of-use.
I didn't have to implement user-configurable showing/hiding of columns. However, it could be done with jqGrid pretty easily: the grid columns are configured in javascript, so you could use code-behind logic during the initial page-build to customize the javascript which defines the column configuration.
I definitely wouldn't return HTML from an ASHX class, since you'd have to craft all the HTML by hand using StringBuilder (or something similar). Makes the code tougher to maintain; and if you ever want to change the page layout, you need to re-compile and re-deploy your system. If you desperately want to return fully-formatted HTML, I would probably use jquery/ajax to just call a .ASPX page. That approach is clunky and heavy-handed - but at least .ASPX is geared toward generating full HTML, unlike .ASHX.
You might want to consider returning JSON instead of XML. It makes for smaller, faster responses over the wire, and is amazingly easy to work with, within javascript. In that case, you should consider using ASMX instead of ASHX to generate the JSON, since it can be configured to automatically serialize your returned object as JSON. That's what I did on my project, and it was very fast and easy to develop.
Finally, I VASTLY prefer jquery and ajax to Microsoft's ajax and updatePanels. This stackoverflow thread details the reasons why.
I think delivering HTML is easier.
But I choose delivering XML to dynamically sort and filter data by using a javascript rendering function like:
function render(options) {
}
The options parameter will be an object that stores orderby parameter and hidden column names such as:
options = {orderby:"name", hidecolumns:["surname", "age"]};
I hope that helps.

Is using jquery to call a WCF Data Service from the UI violating the MVC pattern

I'm fairly new to ASP.Net MVC 2 and understand the MVC pattern in itself. But my question is what's the best way to populate dropdownlists in the UI sticking to the MVC pattern. Should I be going through the controller?
Every article I've seen to do this shows how to do it using javascript and jquery. I have a test application that I'm re-writing in MVC2 I have my dropdowns working with jquery basically calling a WCF Data Service that returns JSON which populates the dropdowns. Seems to me though that this is bypassing the controller and going straight to the model therefore strictly violating the MVC pattern.
Or am I missing something obvious here. You thoughts or best practices would be greatly welcome here.
Thanks
One of the great things about MVC is that the controllers can couple as 'web services' or sort. Meaning, you can easily specify a return type of 'JsonResult' for example (instead of a view - ActionResult).
The MVC framework will handle all the serialization for you.
You can easily call the controller action method from jQuery and populate the dropdown.
In your example, i would create a Json controller method, decorate it with some custom action filters (check http headers that its a json http get request, etc), call it from jQuery and bind to your dropdown.
If your drop-down list is static (i.e. not a cascading drop-down list) then you can add an AvailableItems property to your model, set its value in your controller, and populate the list from that. If your list needs to be updated based on other user selections then you need to call back to an AJAX service of some type.
In general, if your application has script code that runs on the client, that code is going to be in your views. I personally don't see that as a violation of MVC.
I think your best bet is to give View Models a try.
You can build fill out data for special UI oriented models in the controller and pass that to the view. For drop downs, is there a reason you're loading through ajax? In most cases I've found you can just build a normal select list and sprinkle with javascript for dynamical functionality.
Your view model could have a IEnumerable<String> CityNames property that you then load into a dropdown in the view.

Paging search results with asp.net MVC

I have a situation that I couldn't find a solution for through my searches on here. Here is the scenario:
I have a search form with 2 required fields and multiple optional ones. The form posts to an action method that determines which fields are selected and builds a List<> of objects that match the search criteria. I then pass that List<> to the view for display.
This issue I am running into involves how paging is typically done with asp.net mvc. For past projects I have used a custom Html helper that creates links which include the query parameters as well as a "page" parameter. It then uses a GET request and the .Take().Skip() format.
I've hit a wall on this project as I can't use a GET request for the search criteria and I can't figure out a way to keep the List<> in memory to do the usual "page" parameter trick.
I thought about storing the List<> in the session but the objects and the list could be very large.
I would think this is a popular issue with advanced search forms but I can't seem to find a good solution. Any help would be appreciated. Thanks!
How about cacheing the search result object and giving it a unique key. You would then have your paging links reference that unique (SearchID) and have your action look for that object, pull it from cache and Skip/Take from there.
This will not rebuild the object for every request, making page loading much faster and reducing strain on your database/application.
Here is a article about cacheing:
https://web.archive.org/web/20211020111559/https://aspnet.4guysfromrolla.com/articles/100902-1.aspx
Here is a video about cacheing:
http://www.asp.net/learn/Videos/video-6206.aspx
Note: Be sure you specify expiration date on the cached object.
If I understand properly, you only want to load the search results one time, and then page through them.
Have you looked into any jQuery paging functionality? You can just dump the entire list to the page and use JavaScript to handle the paging (and sorting if you like).
An example can be found at http://beckelman.net/demos/jqueryTableSorterConPaging/default.aspx
Put everything in the same form: the required fields, the optional fields, the page links.
Two possibilities:
Use submit buttons or images instead of anchor tags for the page links each having a different name (e.g. page1, page2, ...): this will allow you to get the desired page when the form is submitted.
Put a hidden field inside your form. Then add a javascript click handler to any of the page anchors. This handler will update the value of the hidden field with the page, submit the form and cancel the event.
So clicking on any of the pager links will submit the form with all the data you need to build the list and pager links.

Resources