JavaScript is an increasingly important place on the web, which means more time in the schedule of development. We have to think about how to make it suitable for re-use and easy to support. This can help us to MVC.
MVC term has become familiar in the context of developing the backend using frameworks such as Struts, Ruby on Rails, and CakePHP – MVC origins lie in the structuring of client applications. Let’s see what the MVC, how can we use it, and what is ready MVC frameworks.
What is MVC?
If you do not know what it is, then, after four mentions of this acronym, you probably can not wait to find out. MVC (short for Model-View-Controller) – Is a design pattern that separates an application into three parts: data (Model), presentation of these data to the user (View) and the action performed in response to user activity (Controller).
In 1978, the research center Xerox, formulated the basis of the concept of MVC:Object playing the role model is a computer internal representation of this information. The computer displays the various aspects of this information with the object View, several of the View object associated with the same model can be seen simultaneously. Object Controller translates user commands into messages for the objects of the View and Model.
In other words, when a user does something, it’s “something” passed to the controller, which decides what should happen next. The controller asks the model data and sends them to a form that shows data to the user.
What does this division may give the web developer.
Origins
A static document is the foundation of the web page. This page displays the status information on a server at the time of its creation.
Previously, to modify the data on a server we have created a form in which the user enters new data, then this form is sent to the server and the user is notified that the action is performed. But the constant rebooting the entire page quickly tire the user, especially if he makes a mistake and need to re-introduce all the changes.
Breakthrough
But the dark days of the Web over. JavaScript and Ajax, came to our assistance, we can now modify the individual page elements and report it to the server. Most importantly, we can now respond to user actions, without waiting for server response.
At the present level of JavaScript applications, we arrive at the need to separate components of the application in the style of MVC. Of course, such a separation is not always necessary – sometimes it makes the code unnecessarily voluminous. But, when the application is quite complex, requiring interaction with various parts of the site, the use of pattern MVC, you can create more modular and reusable code.
Structuring the code
Usually, if you want to check the form data, we set the event handler to send the form, which verifies a given field, and informs the user about the bug.
It looks like this:
function validateForm(){ var errorMessage = ‘The following errors were found: <br>’; if (document.getElementById(‘Email’).value.length == 0) { errorMessage += ‘You must supply an email address <br>’; } document.getElementById(‘Message’).innerHTML = errorMessage; }
This approach works, but not very flexible. If you want to add a field or check a different form on another page, you will have to duplicate the functionality for each new field.
Next to the modularity
We make the first step toward modularity and division, adding additional semantics in the form below. Required field containing the email address the code will look like this:
<input type=”Text”>
Now, the script can iterate through all form fields and depending on the attributes stored in the class check field suitable method. Another plus of these classes is that they can be used in the CSS.
We have implemented the metadata on which the script decides how to work with relevant data. But in this approach the data and metadata is strongly associated with markup. In addition, the approach is somewhat limited, it is difficult to describe the conditions by using HTML, for example, what if you need or allowable values for one field depends on the occupancy or value of another field. Of course, the simplest case can be coded in HTML, but it will not be very nice solution, but with the complication of the dependence it is just awful:
<input type=”Checkbox” name=”Other”> Other <textarea></textarea>
In the previous example, the prefix dependson indicates that the binding textarea depends on the occupancy field other. To exclude such construction, let’s try to define all the business logic in JavaScript.
Use JavaScript to describe entities
Despite the fact that we can implement some of the semantics and metadata in HTML, in the end, we have to, as you provide this information at the level of JavaScript.
For example:
var fields = { ‘Other’: { required:true }, ‘Additional’: { ‘Required’: { ‘Other’:{checked:true}, ‘Total’:{between:[1,5]} }, ‘Only-show-if’: { ‘Other’: {checked:true} } } };
In this case, the field additional depends on two other fields, and is displayed only if the user has enabled the checkbox other.
Despite the fact that we have achieved some separation, excessive dependency is still a lot. Checking the data is still related to the display of errors, and the function performs data validation is still associated with the processing of events and is responsible for ensuring that the form was not sent until the data is entered correctly.
Let’s see how we can structure the code using the pattern MVC, and then back to our example with test data form.
Model
Since the MVC pattern consists of three components, we should try to divide our application into at least three main objects.
Select a model in a separate object is simple enough, as we saw in the previous example, this occurs naturally.
Let’s look at another example, we have a calendar of events, details of each event stored in a separate facility. Methods of an object provides an abstract way to interact with the data. Often these methods are called CRUD tasks (create, read, update, delete).
var Events = { get: function (id) { return this.data[id]; }, del: function (id) { delete this.data[id]; AjaxRequest.send(‘/ Events / delete /’ + id); }, data:{ ’112′: { ‘Name’: ‘Party time!’, ‘Date’: ’20010-10-31′ }, ’113′: { ‘Name’: ‘Pressies!’, ‘Date’: ’20010-12-25′ } } metadata: { ‘Name’: { ‘Type’:’Text’, ‘Maxlength’:20 }, ‘Date’: { ‘Type’:’Date’, ‘Between’:[‘2009-01-01′,’2010-01-01’] } } }
The model contains metadata that defines the permissible values of the fields of the event.
In addition CRUD methods remain state of the object on the server, for example, delete function deletes the record locally and sends the request to remove account on the server.
Type
In the pattern, MVC, the form receives the data and determines how to display them. For this purpose he may use an existing HTML, HTML to request a block from the server, or create it using the DOM. Form does not worry about where and how to get data, it only displays the data that refer to it.
View.EventsDialog = function(CalendarEvent) { var html = ‘<div> <h2> {Name} </ h2>’ + ‘<div> {date} </ div> </ div>’; html = html.replace(/\{[^\}]*\}/g, function(key){ return CalendarEvent[key.slice(1,-1)] || ”; }); var el = document.getElementById(‘Eventshell’); el.innerHTML = html; }
Events.data = {
’112′: { ‘Name’: ‘Party time!’, ‘Date’: ’2009-10-31′ },
’113′: { ‘Name’: ‘Pressies!’, ‘Date’: ’2009-12-25′ }
}
View.EventsDialog(Events.data[‘112’]); / / Edits item 112
To controller can control the appearance, not worrying about its internal implementation, we add methods open and close.
View.EventsDialog = function(CalendarEvent){ … } View.EventsDialog.prototype.open = function(){ document.getElementById(‘Eventshell’).style.display = ‘Block’; } View.EventsDialog.prototype.close = function(){ document.getElementById(‘Eventshell’).style.display = ‘None’; }
var dialog = new View.EventsDialog(eventObject);
dialog.open();
dialog.close();
General form
It is easy to succumb to the temptation to make the kind of dependent on data models and methods for their production. However, separating these functions, we make the kind suitable for reuse. If we divide these events and dialogue in our example, the dialogue can be used for any data, not just for the event.
View.Dialog = function(data) { var html = ‘<h2>’ + data.name + ‘</ H2>’; delete data.name; for(var key in data) { html += ‘<div>’ + data[key] + ‘</ Div>’; } var el = document.getElementById(‘Eventshell’); el.innerHTML = html; }
Now we have a common way to view all elements, not just the event, and if the next project need a dialogue, you can use this code without change.
Many JavaScript frameworks designed to meet the independence of the data. YUI controls, jQuery UI, ExtJS, Dojo Dijit and designed with minimal assumptions about data with which they work. As a result of these control elements can be easily used in any application.
Working with the methods of the form
The main rule: form should not call their methods, for example, the dialogue should not open or close itself, it is the controller.
When the user clicks the Save button, the event is passed to the controller, who must decide what to do next form, he can immediately close the dialog, or to say, mind map download progress bar while data is stored, and when the data is stored, the event is complete Ajax call to start another controller method who says, mean that you want to hide the indicator and close the dialog.
Nevertheless, there are situations when the form itself should handle events and invoke its methods. For example, if the dialogue contains a slider that did not need to shift to the controller, handling user interaction with the slider and display its value.
Controller
How did these models come in view? This is a task controller. It is activated, how an event, it may be loading the page or user action for this event handler is associated with the controller methods.
Controllers.EventsEdit = function(event) { / * This event is the event js, and not the calendar event * / / / Event.target.id, contains the ID of the calendar events var id = event.target.id.replace(/ [^ D] /g, ”); var dialog = new View.Dialog( Events.get(id) ); dialog.open(); }
This pattern is especially useful when the data are used in different contexts. For example, we edit a calendar event, click on the Remove button, and now we need to remove dialogue to remove a calendar event on the server.
Controller.EventsDelete = function(event) { var id = event.target.id.replace(/ [^ D] /g, ”); View.Calendar.remove(id); Events.del(id); dialog.close(); }
Action Games controllers are obtained by simple and clear, and this is the key to creating easy-to-application support.
Implement MVC, for example, validation of form data
Now, that we know how to divide the code into its constituent parts, back to the example of checking the form fields from which to start. How can we make it as flexible as using a pattern MVC?
Check the model data
The model defines the data are correct or not, do not worry about how it will be presented, she just need to determine which fields do not comply.
We already have a variable fields containing some metadata models. Now, we add to this object a method that can understand and validate the data passed to it. Method validate enumerates the fields referred to it by the data object and checks whether it needs a certain internal metadata.
var MyModel = { validate: function(data) { var invalidFields = []; for (var key in data) { if (this.metadata[key].required && !data[key]) { invalidFields[invalidFields.length] = { field: key, message: key + ‘Is required.’ }; } } return invalidFields; }, metadata: { ‘Other’: {required: true} } }
To check, we pass an array of key / value pairs, where key is the name of the field, and the value that the user entered into the field.
var data = { ‘Other’: false };
var invalid = MyModel.validate(data);
Now the variable invalid contains a list of fields that are not tested, these data can be transmitted in the form to display error messages.
Displays the fields with errors
Now we need to display an error. The map is a work for the species, and data error, he must obtain from the controller.
View.Message = function(messageData, type){ var el = document.getElementById(‘Message’); el.className = type; var message = ‘<h2> We have something to bring to your attention </ h2>’ + ‘<ul>’; for (var i=0; i < messageData.length; i++) { message += ‘<li>’ + messageData[i] + ‘</ Li>’; } message += ‘</ Ul>’; el.innerHTML = message; } View.Message.prototype.show() { / * Provide a slide-in animation * / }
Additional parameter type lets you specify the class of the element to apply the desired styles.
Bind it all together with the controller
We have a model that stores data and checks them for correctness, and the type that can display an error message or the operation is successful, we now need to relate them to data verification was performed when the user tries to submit the form.
addEvent(document.getElementById(‘Myform’), ‘Submit’, MyController.validateForm);
The method of the controller receives the data, verifying their correctness and displays an error.
MyController.validateForm = function(event){ var data = []; data[‘Other’] = document.getElementById(‘Other’).checked; var invalidFields = MyModel.validate(data);
if (invalid.length) {
event.preventDefault();
/ / Creates a form and displays a message
var message = new View.Message(invalidFields, ‘Error’);
message.show();
}
}
The data array contains the values of the fields. Model checking their correctness and returns a list of fields contain errors. If one field contains an error, save the data is canceled and an error message passed to mind and then he shows it.
Done! Now, we have the reusable type and methods of verification of data models.
Progressive improvement
In our example, MVC is combined with a progressive improvement. JavaScript simply supplements page. Due to separation, a smaller number of components needed to understand what is happening on the page, but it simplifies the use of progressive enhancement.
Often in such applications is first loaded a web page, and then separate Ajax requests are displayed on its data. This can create the user interface seems slow, since before he could work with the page must meet two requests.
To avoid delays, all data is immediately displayed statically, this should be the initial state. The data presented in the initial state, you can duplicate in the form of JavaScript at the bottom of the page and as soon as the page loaded JavaScript part of your application will be ready to work.
You can pre-load and some additional information. For example, in our example, initially displays only the events of this month, but the JavaScript data may contain more and the events preceding and following month, the download time will be affected slightly, but the user can jump to the next and previous month, without requesting data from the server.
Frameworks
Many JavaScript MVC framework provides a much more structured and powerful than the example in the article an approach to the MVC design, but an understanding of the MVC pattern, and as it can be applied, it is important in the case of the development of their own and if you are using an existing framework.
Here are a few examples of such frameworks:
- Trim Junction
Do I need to use the framework in a particular case or not depends on the complexity of the application if the application is very simple, the framework will only be an extra load.
In conclusion,
As always in development, you need to decide whether to use MVC in a specific project. For small applications with limited functionality, it may not be appropriate, but the more your application, the more benefits you get from the separation of code to the model, view and controller.