Using Marionette.Region to Create Bootable Views

I must say right away that my approach is largely based on the approach of the author of screencasts at www.backbonerails.com . This is a very good and useful series of screencasts, not only (and not so much) from the point of view of what is discussed here, but also as a whole for the study of MarionetteJS.
goal
So, our goal is to develop a reusable component for MarionetteJS, which visualizes the loading process. As will be shown later, in the case of the Backbone / Marionette, the events of the start and end of loading can be considered a special case of a change in the state of the model, so the purpose of this component can be formulated more abstractly as a visualization of the change in state of the model.
Getting started with BackboneJS
As everyone knows, MarionetteJS is an add-on for BackboneJS. And I would like to start with how Backbone can help with this task. Suppose we have a model (or collection) and a view that displays it. At the BackboneJS level, we could solve the problem as follows:

Figure 1 - Model events when loading data
That is, a simple idea is that the view observes the model and uses the request and sync events generated by Backbone.Model to go to the "boot" (for example, draw some kind of loading animation) or "Synchronized" state (removes loading animation). For brevity, I will refer to the ability to respond to model state changes such as request, sync, error, etc. responsiveness . By a state change I mean any events that are not related to a change in model data.
In general, Backbone allows us to easily achieve the desired behavior, due to events generated by Backbone.Model (or Backbone.Collection), but there are problems with reusing code that must subscribe to model events and process them. Actually, there are no problems with the question of how to implement responsiveness, the main question is where can this be done so that the use of this implementation is the most unobtrusive and convenient. I will not dwell on further discussion of how it would be possible to implement our component based on Backbone, because in any case it will not work better than based on MarionetteJS.
Using MarionetteJS Views
When I first encountered the task of visualizing the download, I did not think that there would be so few ready-made solutions on this issue. Googling has found some discussion about the implementation of the Marionette.View.loadingView attribute, similar to Marionette.CollectionView.emptyView. Later, some kind of ready- made solution appeared . But to be honest, I think that visualizing a model loading at the level of the view directly displaying that model is not a good idea. In the general case, the method of visualizing the download does not depend on the presentation of the model, but on who displays it. Those. if we display different models in the same place in the document, then the loading visualization should look the same for all of them. In short, this option does not suit us.
We use controllers MarionetteJS
Now it's time to talk about the approach on the basis of which my idea arose. He is described in this issue of the already mentioned series of screencasts. In a nutshell, this approach uses the model as a source of events and a basic abstract controller that determines how views are displayed. Here is a general outline of this approach:
- Responsiveness is directly implemented by a pair of LoadingControler + LoadingView.
- To work with LoadingView, the base controller class method show (view, region, options) is used. Derived controllers should use this method to display views. This method in turn creates an instance of the LoadingController and gives it the original view and the area to display. Next, the LoadingController immediately in its constructor (and not by the request event) substitutes the LoadingView into the specified area.
- LoadingController overlooks the model. Moreover, which is convenient, the model can be omitted explicitly; by default, RealView.collection and RealView.model will be viewed. More specifically, the LoadingController does not view the model, but the xhr objects associated with the data request for that model. Upon completion of these requests, instead of LoadingView, RealView is inserted into the same area.

Figure 2 - Sequence diagram when using LoadingView + LoadingController
Remarks
LoadingController does not work directly with LoadingView and RealView, but through Marionette.Region, but this is not important for a general understanding of the work.
Here is a diagram of the classes that are involved in this interaction:

Figure 3 - Class diagram when using LoadingView + LoadingController
This is the first worthwhile approach that has already been mentioned. But it didn’t suit me for the reason that it imposes some requirements on the general architecture of the application:
- All controllers should inherit from one base class and use only its method to display representations.
- To display the boot view, you must follow the sequence: start loading the model, create a new view, show it.
At the same time, there are very successful solutions that I have borrowed:
- The ability to determine the model to be surveyed without explicitly pointing to it.
- Responsibility for the visualization of the load is beyond the scope of the model.
We use Marionette.Region
Marionette.Region represents a certain area of the screen in which the views are located, and allows you to control the lifetime of the view and to separate from the view the way it appears on the screen. If you want to show a view in an area, you don’t need to think what will happen to the view that is already placed in the area - it will be deleted automatically. If you need to change the way the view appears on the screen, you can simply inherit from Marionette.Region and implement your logic. For example, you can change the way it appears by adding animation, or you can change the way the view is inserted into the document, wrapping it with some of its own elements. For an example, in this releasejust describes the implementation of its own area, wrapping an arbitrary view in a dialog box.
In my implementation, the main work takes place in the abstract class ResponsiveRegion, which is the heir to Marionette.Region. It remains only for concrete classes to define handlers that change the appearance of the region depending on the model events and, possibly, list the events themselves. For example, you can change the transparency, visibility of the elements of the area, insert some kind of overlay with animation - in general, do anything. I will not pay much attention to the design part, but focus on the abstract class. Here's how I implemented area-level responsiveness with ResponsiveRegion:
- Initializing ResponsiveRegion is no different from Marionette.Region. Suppose a Layout view (derived from a LayoutView) that defines a region indicates (declaratively) that our implementation of the ResponsiveRegion region should be used, and not the standard Marionette.Region.
List.Layout = Marionette.LayoutView.extend({ ... regions : { someRegion : { selector : '#region', regionClass : Marionette.ResponsiveVisiblityRegion } } ... });
- To show the view in this area, you can use region.show (view) (as with the usual Marionette.Region), then the default parameters will be used, or you can use region.show (view, options) and specify advanced responsiveness settings.
- The area puts the submitted view into the document. She can do this not directly, but through a wrapper.ExampleСюда помещается исходное представлениеВид при загрузке моделиВид при ошибке загрузки модели
- The area views the model of the view in it (the model is specified either explicitly in region.show (view, options), or RealView.collection and RealView.model are implicitly used). Depending on the request / sync / error event, the scope changes the appearance of its contents. For example, switches the visibility of wrapper elements.
The sequence diagram looks like this:

Figure 4 - The sequence diagram when using the ResponsiveRegion
A classes as follows:

Figure 5 - Class diagram when using ResponsiveRegion
Remarks
Actually, there are still dependencies of Layout and Controller on ResponsiveRegion. The first link is omitted due to the fact that despite the fact that the Layout view actually depends on the ResponsiveRegion, it actually works with it like with the usual Marionette.Region. It’s just more convenient to declare a region type in a Layout declaration. The second link is omitted because it is optional and only occurs if the controller needs to specify responsive options.
What have we achieved by applying this approach?
- We completely fit into the structure of MarionetteJS objects, without creating a single new entity, but only expanding Marionette.Region. ResponsiveRegion in most cases is also used as its ancestor, and does not make any additional assumptions about the components with which it is used. Compared to the previous abstract controller approach, there is no connection with how your application is organized: if you use Marionette, you can use ResponsiveRegion.
- We review the model all the time while its presentation is in ResponsiveRegion. ResponsiveRegion, as the heir to Marionette.Region, is naturally aware of the termination of the submission, which allows him to unsubscribe from model events at the right time and not leave trash behind him.
- We consider the event of the beginning and end of loading the model as a special case of a change in its state, which can occur an arbitrary number of times during the life of the model. This allows you to freely respond to other model events, such as a loading error or validation of model data.
Conclusion
All of the above approaches can be successfully applied depending on the situation. But I believe that to visualize changes in the state of the model in general and load its data in particular, the Marionette.Region option is best suited. Firstly, this is just the component that Marionette is responsible for displaying views on the screen. And secondly, the necessary logic is simple enough so that it can be implemented within one component. That's all. The source code of what was mentioned here and a small example are available here .