@page jquery.model.encapsulate Service Encapsulation @parent jQuery.Model
Models encapsulate your application's raw data. This promotes reuse and provide a standard interface for widgets to talk to services.
The majority of the time, the raw data comes from services your server provides. For example, if you make a request to:
GET /contacts.jsonThe server might return something like:
[{
'id': 1,
'name' : 'Justin Meyer',
'birthday': '1982-10-20'
},
{
'id': 2,
'name' : 'Brian Moschel',
'birthday': '1983-11-10'
}]In most jQuery code, you'll see something like the following to retrieve contacts data:
$.get('/contacts.json',
{type: 'tasty'},
successCallback,
'json')
Instead, model encapsulates (wraps) this request so you call it like:
Contact.findAll({type: 'old'}, successCallback);
And instead of raw data, findAll returns contact instances that let you do things like:
@codestart // destroy the contact contact.destroy()
// update the contact contact.update({name: "Jeremy"})
// create a contact new Contact({name: "Alex"}).save(); @codeend
The Grid demo shows using two different models with the same widget.
@demo jquerypp/model/demo-encapsulate.html
Think of models as a contract for creating, reading, updating, and deleting data.
By filling out a model, you can pass that model to a widget and the widget will use the model as a proxy for your data.
The following chart shows the methods most models provide:
| Create | Contact.create(attrs, success, error) |
| Read | Contact.findAll(params,success,error) Contact.findOne(params, success, error) |
| Update | Contact.update(id, attrs, success, error) |
| Delete | Contact.destroy(id, success, error) |
By filling out these methods, you get the benefits of encapsulation, AND all the other magic Model provides.
There are two ways to fill out these methods:
- providing templated service urls
- implementing the method
If your server is REST-ish, you can simply provide urls to your services.
The following shows filling out a Task model's urls. For each method it shows calling the function, how the service request is made, and what the server's response should look like:
$.Model("Task",{
// Task.findAll({foo: "bar"})
// -> GET /tasks.json?foo=bar
// <- [{id: 1, name: "foo"},{ ... }]
findAll : "/tasks.json",
// Task.findOne({id: 5})
// -> GET /tasks/5.json
findOne : "/tasks/{id}.json",
// new Task({name: 'justin'}).save()
// -> POST /tasks.json id=5
// <- {id : 5}
create : "/tasks.json",
// task.update({name: 'justin'})
// -> PUT /tasks/5.json name=justin
// <- {}
update : "/tasks/{id}.json",
// task.destroy()
// -> DESTROY /tasks/5.json
// <- {}
destroy : "/tasks/{id}.json"
},{})
You can change the HTTP request type by putting a GET, POST, DELETE, PUT like:
$.Model("Todo",{
destroy: "POST /task/delete/{id}.json
},{})
Note: Even if your server doesn't respond with service data in the same way, it's likely that $.Model will be able to figure it out. If not, you can probably overwrite [jQuery.Model.static.models models] or [jQuery.Model.static.model model]. If that doesn't work, you can always implement it yourself.
If providing a url doesn't work for you, you might need to fill out the service method yourself. Before doing this, it's good to have an understanding of jQuery's Ajax converters and deferreds.
Lets see how we might fill out the
Contact.findAll function to work with JSONP:
@codestart $.Model('Contact', { findAll : function(params, success, error){
// do the ajax request
return $.get('/contacts.jsonp',
params,
success,
'jsonp contact.models');
} }, { // Prototype properties of Contact. // We'll learn about this soon! }); @codeend
If we wanted to make a list of contacts, we could do it like:
@codestart Contact.findAll({},function(contacts){ var html = []; for(var i =0; i < contacts.length; i++){ html.push('<li>'+contacts[i].name + '</li>') } $('#contacts').html( html.join('') ); }); @codeend