Storing Models for Reuse

559 views
Skip to first unread message

Shane Harter

unread,
Jul 16, 2012, 10:07:05 PM7/16/12
to chapl...@googlegroups.com
From the Chaplin docs on Github:
 
Per default, a controller is instantiated afresh with every route match. That means models and views are disposed by default even if the new controller is the same as the old controller. To persist models and views, it is recommended to save them in a central store, not on the controller instances.  


So does anybody have any advice on where/how to store model instances?  I mean, i could obviously just store them in a global hash or something. But i wanted to see if anybody whose been down this road has any opinions. 

Thanks,
Shane

Mathias Schäfer

unread,
Jul 17, 2012, 12:50:46 AM7/17/12
to chapl...@googlegroups.com, shane....@gmail.com
Hello,

Am 17.07.12 04:07, schrieb Shane Harter:
Well, it really depends on your individual application and its models.
That’s why Chaplin doesn’t provide a built-in solution. I’ve written a
longer piece on this:
https://github.com/chaplinjs/chaplin/issues/120#issuecomment-6406983


There are probably several types of models and collections in your
application. They usually differ in several aspects:

- How much data they hold
- How often they are loaded and accessed
- How often they change on the server, do they change incrementally
- How important they are in the user flow, whether the user flow can
benefit from caching
- etc.

Depending on these criteria it’s either easy and beneficial to cache the
models on the client side, or it’s rather hard and problematic.


Some examples:

- The logged-in user model. Usually there is just one. It is loaded once
per session and doesn’t hold much data itself. It’s needed virtually
everywhere. Rarely changed on the server side while using the app.
-> It’s safe to cache it as Backbone model in memory as long as the app
runs.

- A collection with fixed categories (like a navigation tree). Loaded
once, pretty much data in total, accessed frequently. Doesn’t change
during the session.
-> Load with app start, hold in memory infinitely.

- A collection of articles on the home page. Accessed quite often during
a session. Much data. Changes often on the server side because new
articles come in.
-> It’s not necessary to hold it in memory as a JavaScript object. But
it does make sense to use HTTP caching properly with a reasonable
expiry. The resource is read from the browser cache the second time,
only the Backbone collection is created from scratch.

- A single article. Accessed once or probably twice. Few data. Rare changes.
-> Don’t cache in memory, rather use HTTP caching.

Sometimes it’s better to hold collections and models in memory to
improve the user experience. For example, the user is reading the
article list at /articles. This list may already contain the full
articles. Clicking on an article should immediately show the full
content at /articles/123 without fetching JSON data from the server.
Most likely the user will return to /articles by using the browser’s
back button. In this case the list view should render immediately.

In this scenario it makes sense to hold the collection in memory as long
as the user stays in this loop. When the user leaves this context, the
list can be purged.


I’m explaining this in-depth to answer how and where to store the
models. It mostly depends on the aspects mentioned above.

In Chaplin, the mediator can be used to store central models like the
user. Just create a property before it’s sealed (in case you seal it,
the example apps do so).

mediator.user = null

Later you may fill it:
mediator.user = new User()

and access it by requiring the mediator module.

See the Facebook app for instance:
https://github.com/chaplinjs/facebook-example


If you want to cache all models of a type since the end of the session,
you can create a hash on the model constructor (CoffeeScript example code):

class Article extends Model

# Static properties/methods
@instances: {}

@find: (id) ->
Article.instances[id] or= new Article {id}

To get an article, you may call Article.find(123).


This is a very simple caching concept with no limit. An alternative
would be an array which just holds the last 10 instances:

class Article extends Model

# Static properties/methods
@instances: []

@find: (id) ->
# Cache lookup
article = _.find Article.instances, (article) -> article.id is id
unless article
article = new Article {id}
# Add to cache
Article.instances.unshift article
# Trim cache
Article.instances = Article.instances.slice 0, 10
article



The same way a model or collection can be saved at a controller
constructor. This is the scenario I’ve described above:

class ArticlesController extends Controller

@collection: null

index: ->
# Don’t save on instance, but on constructor
ArticlesController.collection = new Articles()
# Show list view…

show: (params) ->
article = ArticlesController.collection.get params.id
unless article
article = new Article {id}
ArticlesController.collection.add article
# Show article detail view…

# Chaplin passes the name of the new controller to the dispose
# method so it can decide whether to dispose
dispose: (params, newControllerName) ->
if newControllerName isnt 'articles'
ArticlesController.collection.dispose()
delete ArticlesController.collection
super

This demonstrates how the collection is removed when another controller
takes over. Changing from the index action to show and back won’t remove
the collection.


Just let me know if you got further questions.


Regards,
Mathias

Shane Harter

unread,
Jul 17, 2012, 12:13:00 PM7/17/12
to chapl...@googlegroups.com
Thanks so much for the thorough reply!

Chris Mcvittie

unread,
Oct 23, 2012, 12:30:57 PM10/23/12
to chapl...@googlegroups.com
Hi, 
I hope you don't mind me resurrecting an old thread.  

I'm currently playing with some cases where I have a number of static sub-views, and a number of CollectionViews where the item view would require access to a particular cachable object (a collection in my case).  Effectively I'm looking for "per-controller-action" caching, but as far as I can tell there is no way a view knows about the controller - which tells me I'm probably doing it the wrong way.

I'm curious as to what the best suggested way to handle this could be?

Many thanks, 
Chris
Reply all
Reply to author
Forward
0 new messages