Updates models or collections at the same time although they were fetched asynchronously. Helps to build applications that refresh their user interface at the
Let us say that you build a file system browser that shows the current location, the absolute path and directory contents. You create three Marionette views with three Backbone models which will be fetched asynchronously. If you let the views refresh as soon as their model or collection gets updated, the complete page wil be rendered in three steps, as seen in the animated image above.
// create models
const location = new Node()
const path = new Path(undefined, { current: location })
const contents = new Contents(undefined, { directory: location })
// create views
const locationView = new LocationView({ model: location })
const pathView = new PathView(undefined, { collection: path })
const contentsView = new Contents(undefined, { collection: contents })
// render and show views with empty models and collections
document.body.appendChild(locationView.render().el)
document.body.appendChild(pathView.render().el)
document.body.appendChild(contentsView.render().el)
// request data and let the views update as the data are received
location.fetch(); path.fetch(); contents.fetch()
Marionette refreshes a CollectionView on Backbone collection updates. Refreshing a View on Backbone model changes is the easiest way for simple views. However, if all models and collections are not updated at the same time, views will not be refreshed at the same time either. How to synchronize the update:
- Create one central model to fetch, update other models and collections from the central model. If you take this into account during the design and do not mind the additional models, this is a straightforward way. Later it may not be easy because models and collection referred to by views will not trigger any network communication events.
- Fetch all models silently (passing
{silent: true}
tofetch
) and either re-trigger the events, or render the views directly, when all requests finish. While retaining the view and model class structure, updates will need an extra code, which will be difficult to share, because models may trigger various events on changes. - Do not update view on model and collection changes. Similarly to the previous option, the simple model-view structure will be retained, but updating the view will have to be handled by a custom code. Marionette would have to be modified not to behave as documented.
- Consider fetching of all modules and collections a transaction. Suppress model and collection changes when a transaction has started and perform those, when the transaction has ended. Backbone would have to be modified to offer an API for this.
The last option would look like this:
// create models and views, render and show views with empty data
...
// request data and update the models and collections when all are ready
location.startTransaction(); path.startTransaction(); contents.startTransaction()
Promise
.allSettled([location.fetch(), path.fetch(), contents.fetch()])
.then(() => { location.commit(); path.commit(); contents.commit() })
This pattern of starting a transaction, fetching the data and committing the changes on multiple models can be encapsulated to a helper function:
// create models and views, render and show views with empty data
...
// request data and update the models and collections when all are ready
fetchWithTransaction([location, path, contents])
TODO
Encapsulates fetching of multiple models and collection in a transaction:
- Executes
startTransaction
on each model or collection. - Executes
fetch
on each model or collection passing theoptions
argument to them, and waits until all their promises are settled. - If all promises above were fulfilled, executes
commit
on each model or collection. - If some promises above were rejected, checks the value of
options.rollbackOnError
/ If it is nottrue
(default) executescommit
on each model or collection, otherwiserollback
.
The output promise will be settled with promise results of previous fetch
calls. If all of them were fulfilled, the output promise will be fulfilled, otherwise rejected.