-
Notifications
You must be signed in to change notification settings - Fork 421
recipes_models
@page RecipesModels Models @parent Recipes 3
@body
The following recipes show how to use can.Model
(and often the can.fixture
plugin).
The following recipe shows how can.Model
's internal store and can.view
's live-binding
can easily solve the editing-data-that-is-represented-two-places problem. It
shows two task lists of overlaping data. Notice how the "do dishes" is listed
twice. But if you click one "do dishes" checkbox, it updates the other.
The code first sets up a can.fixture
to return different, but overlapping lists of
tasks from the server. The fixture returns data from the following calls:
/tasks?due=today
/tasks?type=critical
You'll notice "do dishes" in both lists.
The code then creates a Task
model that maps findAll to /tasks
. It then uses
can.view
to render the retrieved tasks with the tasksEJS
template.
Finally, it listens when an input
element's value changes. When it does,
it gets the task model instance from the li
element's $.data
and
updates it's "complete" property.
The Secret Sauce
Model keeps an internal, non-leaking, store of instances your app loads. When
Task.findAll({type: "critical"})
and Task.findAll({due: "today"})
get their
raw JSON data from the server, they convert it to instances. But before they create
a new instance, they check if the same instance, matched by
the id property already exists. If it
does, it uses that instance.
This means that the criticalTasks
list and todaysTasks
list both point to the
same instance. When can.EJS
does it's live binding on <%= task.attr("complete") ? "checked" : "" %>
it's actually binding on the same "do dishes" intance once. So updating "do dishes" updates
the DOM in two places!
The following recipe shows how can.Model
can be used to create an ORM-like
model layer for keeping a local copy of a restful API. This type of base model
is perfect for situations where you want a responsive UI, but may not want to
wait for updates from the server before displaying data, or you need to make
your data persist offline. Storing your responses in localStorage
allows you
to get data to the view as quickly as possible.
When creating your base model for other models to extend from, you can prefix
static service methods with make
, to allow the base model to define how the
extending model's method will behave. In this example, our base model implements
a static method called makeFindOne
. This method acts as a hook to define the
extending model's findOne
method. Using this, we can create a middleware-like
layer between the extending model and the base model that loads and saves model
data to localStorage
, while still requesting out to the restful API to get
updates.
The Secret Sauce
The secret sauce for this example is the static makeFindOne
method along with
EJS's live binding. Because the live binding will automatically update the view when the
bound model gets updated, we can write our code as usual and allow the base model
to deliver localStorage
data instantly, while automatically upating with responses
from the server, with no extra effort.
Type a message in one page, it instantly shows up in the other.
<iframe style="width: 100%; height: 300px" src="http://jsfiddle.net/fbasrawala/yRMSa/embedded/result%2Cjs/" allowfullscreen="allowfullscreen" frameborder="0">JSFiddle</iframe> <iframe style="width: 100%; height: 300px" src="http://jsfiddle.net/fbasrawala/yRMSa/embedded/result%2Cjs/" allowfullscreen="allowfullscreen" frameborder="0">JSFiddle</iframe>