JavaScript and MVC


For some reason, despite understanding a programming concept in one language can make it difficult to understand it in a different language, especially if it differs a lot from the one you know.

JavaScript is a good example of this. From experience I can say that grasping the concepts of things like MVC in JS can be slightly difficult at first.

When you are working with some highly interactive “Web 2.0” sites, you may need things like Ajax-based forms and inline editing. Maybe you can add things to a list with a dynamic form, which submits the data to the server with Ajax… Then you might have multiple listings, which may or may not need to be updated based on what you just saved.

Making a request to the server in a case like this to update all the lists is just a bit pointless, but updating them all with JS can lead to confusion. What would be the best way to approach something like this?

MVC and Events

In desktop applications, MVC has been used for a long time. But how would you go about using MVC in JavaScript?

Let’s look at an example: If you have programmed in .NET languages, you probably have used Data Binding, which is a way to bind form controls (the view), such as a data grid, to some dataset (the model), like a database query.

Now, when the dataset updates, the controls that are bound to it will get automatic notifications and will update themselves.

If you’re more familiar with languages like PHP, such event-based programming may be a bit hazy, since you can’t really do things like that, as it isn’t very useful in most cases. But, a language like JavaScript, which is constantly running on the browser, can utilize this approach. Since you can have some data in your JS application which changes without actually reloading the page and so on, event-based programming can be very useful.

The model

How would you design a model layer in JavaScript, which does not really have access to databases or such?

In the very simplest approach, the model could simply be an object which has an array of data, and provides some methods for modifying and getting the data. It should also provide a way for other classes to subscribe to some basic events: new data, data modified, data deleted or such. The model will also need to fire these events when the actions occur.

This way we can have a single data store. When your forms or other things add new data, they will only need to update the data store. All other objects, like data grids or lists, can subscribe to the events, and they will automatically get notified on updates.

What about actually sending the data to the server, then? You could simply create an Ajax class which also subscribes to the data stores events and sends calls to the server.

The views

You may be wondering how would you make tables or lists subscribe to events, since HTML can’t do that!

This will also require some JS magic. You’ll need to create classes that can subscribe to the events, and then update the HTML/DOM. The most preferred approach to this would be something that will allow you to add these classes to HTML afterwards. This way you will ensure that even users with no JavaScript support will at least see the non-dynamic tables, lists and other things.

A simple method would be to make a class which can generate a table based on some data. You should also be able to assign this class a container where it will output the resulting HTML. It might also be a good idea to make it able to load the initial data from the markup – that way you can add custom features, such as sortable columns, without having to load the data from the server or anything.

The class should (obviously) be also able to subscribe to those events provided by our model.

Some considerations

There are some things that need to be considered here:

  1. How to tell the user whether the data has been really saved or not? This is very important! I have used some nice JS based interfaces, but they wouldn’t tell me when an Ajax-call to the server failed. It would look like I just did something, but when I reloaded the page, the change would not show anymore.
  2. Where to get the initial data to the model? Since your view classes would depend on the data in the model, where do you go to get the initial data to the model? If we are progressively enhancing the page, there will be some initial data in the HTML code. Should we try to interpret the data from here, or should we just make a request to the server and get the data in JSON?

Options for #1 are a two-sided blade: You could immediately update the UI, and give the impression of speed, which is always a good thing. This could end up causing problems when the save fails – the UI would show the data, but the data would not be stored.

The second approach to #1 would be to not update the UI before the request is complete. This might leave the user thinking Did anything happen?. A better version of this would be to place a loading indicator on the UI where the data should appear. This will tell the user that there’s actually something going on, but on the other hand it will require tighter association with Ajax and the data store.

The approaches for #2 also have some advantages and disadvantages. Loading the initial data from HTML can be faster and maybe relieve some stress from the server. As you can probably guess, it is also a lot more complicated to code. The JSON-based way can be slower and it will require you to do an additional request to the server. Another problem with that can be that what happens when you load the data? If the user had already done something to the views, what happens?

In closing

Whatever you decide, it’s always a good idea to take a good JS library along. It should at least give you good methods for OOP, Ajax and events. You probably would not want to implement everything regarding event handling yourself as there are a lot of holes to fall into.

If you want to look for inspiration in regards to the data store – views approach, you should check out Ext JS. It has a very nice implementation of this which works very nicely with their datagrids.