Hi, Habr.
This article will discuss what Marionette.js consists of and how to not write your bike.
The article is intended primarily for those who worked with Backbone.js and / or Marionette.js.
For the first acquaintance, the first, overview, part and links at the end of the article will be useful.
First, let's remember what Backbone.js is and what it consists of.- Underscore.js - more than 80 helper functions for convenient, cross-browser work with JavaScript.
- Backbone.Events is an implementation of a base event class plus helper functions for associating (bind) events with objects.
- Backbone.Model is a data model with access to key / value attributes. It has a download / synchronization mechanism with the server.
- Backbone.Collection - collections of models spiced with 28 methods from Underscore.js. Like the models, they have a download / synchronization mechanism with the server.
- Backbone.Router and Backbone.history - basic router and page history. Able to detect the coincided path and produce navigation.
- Backbone.sync - implementation of loading / synchronizing data through REST using jQuery.ajax.
- Backbone.View - view. Out of the box, he can neither render himself nor insert a tree into the DOM.
Part One: Marionette.js
Imagine that we are writing an application on Backbone.js. As a result, we get:
')
- The basic representation that implements support for the template we need and the relationships we need with the models;
- The thing that renders the view and inserts it into the DOM tree;
- A piece that can display collections;
- The thing that is responsible for the life cycle of the views;
- Expansion over the router;
- The stuff that launches our application;
- A modular system, whether it be source folders or one of the implementations of JavaScript modules;
- Most likely, anything else.
The term "piece" can be understood as various architectural implementations of the necessary functions.
At the last BackboneConf conference, the idea was repeatedly voiced that Backbone.js is the basis (skeleton) for writing the framework. Moreover, the basis is quite good.
Marionette.js is one of the libraries that, using all the flexibility of Backbone.js, creates a sketch of the architecture and implements the basis for writing large web applications.
Read more about what Marionette.js consists of (with pictures):
Backbone
- Everything that Backbone.js provides us, we can use in Marionette.js. Exceptions are Backbone.View views; it makes no sense to use them, since they are not compatible with the Marionette.js mechanism to add to the DOM tree.
Representation
- Marionette.View is the base class for all Marionette.js views. Implements the functions of working with DOM elements and their events. Not intended for direct use.
- Marionette.ItemView is a view for rendering data on a single template. Data can be either one model or one collection. If the data is represented by a collection, then all its elements will be transferred to the template by an array.
- Marionette.CollectionView - the view runs through all elements of the collection and renders an ItemView for each. This type of view does not have its own template; each ItemView is added to the “el” container of the CollectionView.
- Marionette.CompositeView is the same as CollectionView, plus its own template and data model for the container. We must explicitly specify a container element to add an itemview. Suitable, for example, to display a model of “search conditions” and a collection of found records.
- Marionette.Layout is a view that displays an arbitrary template with data as an ItemView, plus it creates a regional manager, which will be discussed below.
Performance Management
- Backbone.BabySitter is a container for managing child views. Used in CollectionView and CompositeView. Can be used with Backbone.View without Marionette.js.
- Marionette.Region - management of the region (region) on the page. In simple words, a region is an object that contains one html element and can insert html contents of other views into it. At one time, the region displays only one view. When you add a new view to the region, the old html content is deleted and the view object itself is closed.
- Marionette.RegionManager - manage a group of regions.
- Marionette.Renderer - implementation of html rendering from a template and data. Used in all views of Marionette.js.
- Marionette.TemplateCache - lazy loading and cache of underscore templates. Used by Marionette.Renderer. To use a different template engine, it is recommended to override Renderer and / or TemplateCache.
Modules and Application
- Marionette.Module - modules are not designed to track dependencies and are not related to the application build, unlike AMD / CommonJS modules. The Marionette.js module performs the following tasks important for client-side JavaScript: starting and stopping the logical part of the application, an elegant namespace with the possibility of describing one module in several files.
- Marionette.Application - the application can be described as the root module and the base manager of the regions. It has a set of message buses and a launch mechanism for all modules.
- Marionette.Controller - literal translation: a general-purpose object for managing modules, routers and views. Implements the mediator pattern (mediator). More information about the controller / mediator - below.
Tire posts
- Application.vent is a global instance of Backbone.Wreqr.EventAggregator. Implements the pub / sub pattern. Subscribers and publishers can be any number.
- Application.commands is a global instance of Backbone.Wreqr.Commands. You can only subscribe to a specific command once. If a team is sent before creating an “artist”, it will be executed when it is created.
- Application.reqres is a global instance of Backbone.Wreqr.RequestResponse. Implements the request / response pattern. Only one subscriber can execute the request.
Rest
- Marionette.AppRouter - routers in Marionette.js should be thin, there should not be a “global” router of everything. The task of the router is to call the desired controller method when the path matches, no business logic.
- Marionette.Callbacks is an internal call chain call assistant.
Conclusion: do not write your framework, use Marionette.js.
Part Two: Controller / Mediator
I strongly advise you to watch all 9 hours of screenbaster BackboneRails from Brian Mann. Materials contain a huge number of useful pieces, one of which is a detailed description of the use of the controller / mediator.
The basic idea: the life cycle of each view or a logically related group of views (Layout) is controlled by a controller / mediator.
A detailed example: we need to display a list, let it be a list of "Apples".
We are creating a new Apple list controller. The controller, in turn, has the following tasks:
- Request the necessary data (from the data provider via the message bus);
- Wait for data download, possibly showing a download spinner;
- In the case of the Apple list, display a CollectionView or CompositeView;
- Listen to events of the displayed view, for example, clicks on the recording of each apple;
- If necessary, redirect events to the global message bus;
- When closing a view, close yourself;
- When you close yourself, close all your subscriptions (bind) to events.
More on the first paragraph
The logic of “how to wait for the data, transferred from the data provider to the controller / mediator, allows us to process this in the most appropriate way for the user interface. For example, in one case we can spin the spinner and after receiving the data display everything, and in the other case, first display the empty representation, and then fill it with the received data.
More on the fifth paragraph
It seemed that one could directly send view events to the global event bus. But the layer in the form of a controller / mediator allows us to use the presentation events to the full and proxy the events that are necessary only for the entire application. Example: for apples, you can use the “delete apple” button in this list and the confirmation dialog (“do you really want to delete this apple?”) As an example; only after these two events processed by the controller / mediator, do we send messages to the global bus that an apple has been removed.
Conclusion: the controller / mediator that implements the mediator pattern (mediator) is excellent for the role of a link of asynchronous data, rendering of views and user actions.
Links and materials: