Posting Form Content via JavaScript

Web-based applications run smoother if instead of using the traditional form method, they use JavaScript to post data to the server and to update the user interface after posting data: It also makes it easier to keep POST and GET actions separated. SignalR makes it even slicker; it can even update multiple pages at the same time. Is it time to use JavaScript to post data rather than posting via the browser the traditional way?

The great proportion of web sites out there use HTML forms to post data. When a user clicks one of the submit buttons that may be defined in a form, the browser automatically scans the input fields within the boundaries of the FORM element, serializes their content to a string and sets up a HTTP POST command to the target URL. The target URL processes the posted content and typically serves back a new HTML page. Any feedback about the processing of the posted data is incorporated in the returned page.

This approach worked for decades and still works well; but it is, more and more, perceived as cumbersome and slow as the boundaries of web technology are pushed. The alternative is to post content via JavaScript.

Technical Aspects of Posting Forms via JavaScript

Regardless of the specific framework you use, whether it’s plain jQuery or a much more sophisticated framework like Angular, the steps to take to post a HTML form with JavaScript can be summarized as below:

  1. Collect the data to post from the input fields of the form
  2. Serialize individual field values into a stream of data that can be packaged into a HTTP request
  3. Prepare and run the Ajax call
  4. Receive response, check for errors and adjust the user interface accordingly

Apparently, the first two steps are fairly bothersome to write as you need to put together a line of JavaScript for each input field and then serialize values to a string. Here’s an example.

Imagine a similar line repeated for each input field. In addition, if you’re using richer input controls that don’t directly map to input controls (ad hoc date or time pickers for example) then read expressions can be even harder to write.

The next step consists of building the string that will go into the body of the HTTP request and concatenating posted values with parameter names. The pattern of the string is the following.

In this regard, the jQuery library helps by offering some shortcuts. An interesting one is the serialize function you can call on a FORM element.

Another option in jQuery is the $.param function. The function produces the same output as serialize except that it accepts a different type of input. Whereas serialize can only be called on a form and automatically scans the list of input fields, $.param accepts arrays and name/value dictionaries and produces the same output.

Once you have the form data serialized, you can arrange the canonical Ajax call, as below.

The Ajax function allows you to pass in two callbacks to handle the success or failure of the request. It is worth noticing that ‘success’ or ‘failure’ refers to the “request” and not to the business operation behind the physical HTTP request. Let’s have a look at a possible ASP.NET MVC endpoint getting invoked via Ajax and JavaScript. As an example, consider a login request.

The method receives posted data in an instance of the sample LoginInputModel class via ASP.NET MVC model binding, and uses some logic to try to authenticate the user via the credentials provided. The method TryAuthenticate returns some response that, we can assume, includes two key pieces of information: whether the operation failed or not, and a message for the user. If authentication was successful, then the response that goes back to the Ajax caller is the return URL to redirect the user after a successful login. Otherwise, it is the message(s) to present to the user as feedback.

It goes without saying that you can change the format of the response that is being returned through the Ajax call and make it, for example, a more complex JSON object. However, what’s key to remark here is that from a pure HTTP perspective, the HTTP status code is still 200 whether the authentication was successful or failed. This means that the error callback on the Ajax call won’t be invoked. That will be invoked only if the status code is different from 200. If you prefer to have the Ajax error handler involved in the management of possible failure then you must throw an exception in your ASP.NET MVC controller.

Let’s see now how to deal with the server response within the Ajax callback handlers.

Dealing with Received Feedback

The callback handlers, whether for the success or error case, receive data and are responsible for displaying that. It requires unpacking and splitting data across the various pieces of the HTML user interface. In other words, you must refresh the current DOM via data-binding.

If the form post was successful, then you might want to show users a reassuring message like “The operation completed successfully”. Even more importantly, if the form post resulted in a functional failure then you might want to provide details that typically indicate that some input data was incorrect.

Should these messages be there on the screen indefinitely until the next operation is attempted? Error messages might reasonably remain on screen until the next submission, but at some point they must be removed. You can perform this step before you submit the form again via Ajax or leave them there and just replace them with new messages or clear all if the operation ended successfully.

Things are slightly different, in my opinion, for a successful message. It’s important to show a confirmation message but the message must not be invasive nor being around for too long. I’d definitely avoid modal popups here and would tend to prefer to bind the message to a timer so that it first appears as a piece of text interspersed with regular user interface, and is then dismissed a few seconds later without any user intervention.

Some sort of middle ground is reached by displaying the message in a DIV that looks like an alert box and give users a chance to dismiss it by simply clicking. When I take this route, I typically use the Bootstrap alert class to style the container of the message and use the following chunk of JavaScript in the global layout so that it automatically applies to all alert boxes and makes all of them easily dismissible.

Note that dismissible alert boxes are also supported natively by Bootstrap but I find this trick quicker to write and cleaner.

What’s Different with Angular?

You also use Angular to post your HTML forms without fully-refreshing the browser’s view. Most of the time, Angular allows you to write cleaner code than with plain jQuery but it is important to note that Angular can’t do magic. In an Angular page, once you’ve set up modules and controllers and completed binding between view model properties and DOM elements, you are left writing a function like the one below:

The object formData is defined in the Angular controller and may be configured to be filled automatically via data binding with input fields.

The ng-model directive does the trick of adding a userName property to the formData object and keeping it in sync with what the user types in the input field. Frankly, this is not really different from using the jQuery serialize method to streamline the form content to a string.

Angular, however, proves a bit more beneficial than plain jQuery when it comes to handling the response. In Angular, you have no need to write JavaScript code to set values on each DOM element that needs to be updated. For this you can effectively leverage the power of the data binding model of Angular. To display an error message close to an input field, you can do the following:

The combined effect of Angular directives ng-show and ng-class greatly simplifies the code and keeps any reference to UI elements away from your JavaScript. Functionally speaking, such JavaScript logic is still required but it’s now buried in Angular and references to UI elements are captured via attributes rather than by ID. The ng-show directive manages the visibility of the DOM element and shows it only if the specified property in the attached view model has a non-null value. Similarly, the ng-class directive attaches the specified CSS class (has-error in the example) if the specified property has a non-null value.

More on Updating the User Interface

In a recent article “Keeping POST and GET Separated”, I discussed the Post-Redirect-Get pattern and the benefits you can derive from posting data and reading response over two consecutive and distinct requests. The usefulness of the PRG pattern on top of standard web programming techniques is mitigated by the fact that you have to work out a way to pass data back to the caller after successfully posting a form. Microsoft offers the TempData dictionary for the purpose and the dictionary works beautifully except that it is a potential blocker of scalability. In its default implementation, in fact, the TempData dictionary relies on session state and because of that it may become a silent killer of horizontal scalability. When session state is used-whether explicitly through the Session object or implicitly through TempData-some user-specific information is saved to the memory of the worker process that serves the request. As you add up more servers (horizontal scalability) there’s no guarantee that the next request will be served by the same server machine where you just saved valuable session data.

Some workarounds exists to this problem. One is using an alternate implementation of TempDatathat doesn’t use session state (i.e., cookies or local web storage or even shared cache or database). Another workaround might be configuring the web farm to support sticky sessions. In this case, you explicitly tell the system load balancer to ensure that requests served from a specific server will always return to it. (See http://goo.gl/VyTQ4r) Posting the content of a form via JavaScript as discussed so far would make TempDataunnecessary, but you won’t have any more POST and GET separated. So the question becomes: is there a way to keep POST and GET separated without having to resort to the TempDatadictionary to update the user interface? Yes, if you consider using SignalR to refresh the user interface.

Bringing ASP.NET SignalR to the Table

ASP.NET SignalR allows you to signal the occurrence of a server side event and push freshly generated data to all, or some, connected clients. The post of the form data via JavaScript causes an update of the current state of the system but nothing else. The success callback may do nothing, or it may just show a reassuring message such as “the data has been queued for processing”. The error callback, instead, kicks in only if there’s a network-level failure or an internal error occurs. The server-side endpoint that is invoked via JavaScript to process the content of the form will have the following skeleton:

Let’s say you are writing the portion of a web site that updates the profile of a user. Using JavaScript, you handle the client-side click event and post a request to the Update method. The ASP.NET MVC model binding layer maps incoming data to a newly created instance of the MemberProfile class. This instance is passed down the stack to actually alter the state of the system. A response is returned that contains a few pieces of information such as a Boolean value that indicates whether the operation completed successfully and in this case you use the SignalR hub to broadcast changes to any client that is listening.

You can code the client side SignalR component in a few possible ways. You can simply have it to receive a notification that changes can be applied to the current view or you can pass directly the changed data to display. In the former case, you don’t need any JavaScript logic to update the page. The client SignalR component will place a GET to some controller to have the current page refreshed. This refresh request can go through the browser or via Ajax. If it goes through the browser you would use the following JavaScript code:

Otherwise you will have a method on the ASP.NET MVC controller that returns JSON or an HTML partial view to quickly refresh the user interface.

In alternative, the SignalR push notification may already include any changed data that is critical to show in the user interface right away. In this case, you need some JavaScript code in the SignalR component that updates DOM elements one after the next.

Summary

Posting data via JavaScript is definitely possible and overall makes the entire user experience much smoother. By using SignalR to update the user interface after posting data, you keep POST and GET actions substantially separated. You can also, via the broadcast mechanism of SignalR, update multiple pages at the same time. For example, when users update their profiles, Not only can you refresh the user’s profile page but also the public page of the user that other users might be viewing at the same time. It isn’t yet the time to consider that posting via the browser the traditional way is an obsolete practice, but for sure the costs of doing it all via JavaScript are lowering every day and you don’t need a huge framework like Angular to achieve that.

Tags: , , ,

  • 8771 views

  • Rate
    [Total: 0    Average: 0/5]
  • MartyP

    PostBacks Are Dead
    In the wise words of a friend of mine, ‘When do you back to the server? Only when you need data!’
    I really like this article and it has been my mantra for a long time. I gave up on full-page postbacks back in 2004 when I first learned about the HTTPXMLRequest object and AJAX. Unfortunately, JQuery was little-known back then so I have since written many, many JScript routines to accomplish these same tasks. What I like about this article is it is a more modern(?) spin on incorporating these same methodologies into the frameworks that are used more recently (MVC and Angular). Unfortunately, I have never really needed these tools (except that my employer likes them) because I send my data requests directly to custom controls on the server. In doing this, I can retrieve data, a partial page (DIV), or clear text; each in its own ascx. I rarely have a need for any more than one aspx in my projects.
    Now, I want to try taking my old-fashioned methods and applying these techniques to them.
    Thank you.

  • MartyP

    Typos
    Sorry about the typos. I meant ‘When do you GO back…’
    And, its XMLHttpRequest.

  • David

    Javascript to POST/upload files?
    Forms are also used to upload files. Any tips to share using javascript/jQuery/AJAX to replace the old form POST upload file method?

  • Glen Hassell

    “you don’t need a huge framework like Angular” – < 36kb.. most site's contain pages, which have bigger image's to load.