Guides

More

One of the challenges with moving state to the client-side is data management. Data management in stateful JavaScript applications is a completely different matter to how it's normally handled in conventional server side apps. There’s no request/response model, and you don’t have access to server-side variables. Instead, data is fetched remotely and stored temporarily on the client-side. This has the advantage that data access is immediate, and users are rarely, if ever, left waiting for remote data to load.

After the initial page load, remote data is stored locally in class structures called models. Models are the core to Spine, and absolutely critical to your applications. Not only do they store all the application's data, but they are also where any logic associated with that data is kept.

Models should be de-coupled from the rest of your application, and completely independent. Model data can be persisted with HTML5 Local Storage or Ajax.

If find() fails to retrieve a record the default behaviour is for null to be returned. it up to you to check if anything is returned. alternately you can check for the existence of records by calling exists().

assert( Contact.exists( contact.id ) )

You also have the option to define a custom notFound() method on your Model. This method is called in the event find fails for the id it was given. You could have notFound() throw an exception (to mimic behavior of older versions of Spine) or you may want check a remote data source for the record.

If you're using an older browser which doesn't have native JSON support (i.e. IE 7), you'll need to include json2.js which adds legacy support.

Persistence

While storing records in memory is useful for quick retrieval, persisting them in one way or another is often required. Spine includes a number of pre-existing storage modules, such as Ajax and HTML5 Local Storage, which you can use for persistence. Please check out the Ajax and Local Storage guides) for more information.

If you want to pull from one of these sources to populate your model collection use fetch()

Contact.fetch()

Events

You've already seen that models have some events associated with them, such as error and ajaxError, but what about callbacks to create/update/destroy operations? Well, conveniently Spine includes those too, allowing you to bind to the following events:

save - record was saved (either created/updated)

update - record was updated

create - record was created

destroy - record was destroyed

change - any of the above, record was created/updated/destroyed

refresh - when records are invalidated or appended using the refresh method

error - validation failed

For example, you can bind to a model's create event like so:

//= CoffeeScript
Contact.bind "create", (newRecord) ->
# New record was created

For model level callbacks, any associated record is always passed to the callback. The other option is to bind to the event directly on the record.

The callback's context will be the record that the event listener was placed on. You'll find model events crucial when it comes to binding records to the view, making sure the view is kept in sync with your application's data.

If you want to remove events, you can unbind specific events by calling unbind() on the Model. See the event documentation for more information on how you should use unbind(). Model instances also have an unbind() function, but it can only be used to remove every event listener associated with that instance.

Dynamic records

One rather neat addition to Spine's models is dynamic records, which use prototypal inheritance to stay updated. Any calls to find(), all(), first(), last() etc, and model event callbacks return a clone of the saved record. This means that whenever a record is updated, all of its clones will immediately reflect that update.

Let's give you a code example; we're going to create an asset, and a clone of that asset. You'll notice that when the asset is updated, the clone has also automatically changed.