When you start to look at the documentation on KnockoutJS, before getting an explanation on what an observable is and how it works, you get the explanation of the presentation pattern that is used with KnockoutJS. You can live without this explanation, but it can help you to understand why we are using it and how you should organize your project when you use this pattern.
As you can read on the KnockoutJS website, MVVM is a design pattern for building user interfaces. Here, you can find a short description about this pattern and what each term means. Instead of repeating the same information, I suggest you check this URL before moving on: http://knockoutjs.com/documentation/observables.html#mvvm_and_view_models.
Let's discuss this design pattern in more detail in the following section. To understand what MVVM is and why someone invented this pattern, we have to discuss its origin: Model-View-Controller (MVC).
MVC is an architectural design pattern that enforces separation of concern; it isolates business data (models) from the user interface (views) using a third component (controllers) which manages the logic and the user input, and coordinates the models and the views.
It was a really well-done pattern, but then we changed context, and we needed a pattern for the web.
There are a few server-side implementations of MVC for the web, and in each of them you can find how the controllers stay on the server, managing the user input, modifying the model, and then sending a new view to the client.
The main drawback of this kind of implementation is that you can find it a bit static and not so responsive.
The first way people solved this problem was by using AJAX heavily to update the client without refreshing the page; in this way, you get all the benefits of server MVCs in the context of the web development.
After that, a new kind of application was built: SPA. In such an application, you use a client router which manages the transition between pages directly on the client-side, keeping all the states and reusing all the information the client already has, avoiding a data trip from the server to the client for each request.
Then, a new problem arose: too much complexity and spaghetti code to keep the client and server synchronized, using jQuery and AJAX.
The client-side implementation of MVC is realized in this way:
The Models keep the data, the Views show the information to the user getting the data from the Models, and the Controllers manage the user interaction and the update of the Models.
The Views know about the Models; they listen to the Models to show the most updated data. This means we are tightly coupling Views and Controllers (so a change to one affects the other), and they are closely coupled to the Models (a change to the Model affects both the View and the Controller).
The Controllers have to register the interaction of the Views by themselves, so they are full of interaction code instead of having all the management logic.
Another consequence of the previous point; the Views are tightly coupled with the Controllers because the most commonly used way to reference the Views element is by ID with jQuery selectors, and any changes to the DOM structure will impact the relative Controller.
I'm not saying MVC is not a good pattern, but that maybe we can find something better for web development.
The main idea behind this pattern is that in the MVC the View knows too much about the Model, and someone should manage all the data transformation.
Think about this: in our database we keep the date of the creation of a product; when we load our model from the server we get this information, as a Date object. In the view,
small.html, we want to show this date with a short format, and in the view
big.html we want to show it in the long format; where do you put all this information?
With the MVC you can have a single Date object and the View can have a code-behind converter; or you can have all the three Dates pre-formatted inside the Model; or the Controller can set the format inside the View when it decides which View to show and initialize.
As you can see in this example, a problem with MVC is that all the View-related data not directly found inside the Model has no home.
The MVVM pattern works differently, as you can see in this picture:
Here, the Model keeps the data from your business logic and works by itself.
The View Model knows the Model, and it can use it and expose it (and other property not Model-related like a date pre-formatted, or the color of the theme if you give the User a way to change it) to whatever View want to use it; and it doesn't need to know anything about the View.
The View ignores the Model, and uses the View Model to get the information to render and to manage the user interaction.
So, briefly, the Views and the Models send events to the View Model, and the View Model updates the Views and the Models directly.
Let's review all the components of this pattern.
In our project, we need to represent jewelry products with description, images, and so on; so our models will be Product (to describe the name, the description, the images, and all the other data related to our jewelry), Category (because all the products will have a category, and each category should have a name and other information), Cart (because it will be the container of the product the customer wants to buy).
In a more generic vision, the Models are all the objects you think about when you have to describe your product; in a web application you get them from the server, maybe in a database.
Another kind of model data is the information about the user. Let's think about a website with a registration form; in that case the user data will be part of the model, and probably you'll create a model class, User.
When you use KnockoutJS, your Views will be done with HTML and you'll put data-bind attributes to relate to the View Model.
index.html, which we wrote in the previous section, is one of the Views we will make.
Try to think about
index view and
product detail view.
We have the same Model for both the views, but in
index view we show only a thumbnail of the product, and in
product detail view we show only the big images.
In MVVM, the View doesn't need a reference to the View Model, nor the View Model should know there is a View, because the data binding library will keep both synchronized.
A really good consequence of this last point is that you can easily test the View Models and Models without having to mock any View.
Data binding is really useful and simplifies your code because of the separation of the concern; the main drawback of this functionality is that it generates a small overhead; let's understand why.
You have a View Model with an observable property,
The data binding design pattern is deeply bound to the Observer pattern; KnockoutJS maps the observables using the data-bind attribute, and the observers are the View Model properties.
When you define this property, the data binding system must keep this information: List of observers
Create a context object (an object keeping references to the parent context, to the root context, and to the data)
Evaluate the expression inside the context (in this case, a property, but it can be a full expression)
Add itself to the list of observers for each referred observable found inside the expression
So, just for this binding, we are adding:
Memory occupation: A list with an item and an object with at least three properties (parent, root, and data)
CPU: The creation of the context and the evaluation of the binding
As you can see, when you build really big application you must start thinking about which object should be observable, to optimize the system.
Better testability of business and application code
Low coupling between components, which gives more freedom to the UI designer to redesign a webpage without the fear of breaking everything
I hope now you understand this pattern better and how to use it in the best way.
We will see better what you should put inside each component during development.