can
Version:
MIT-licensed, client-side, JavaScript framework that makes building rich web applications easy.
158 lines (109 loc) • 4.8 kB
Markdown
@constructor can.Model.List
@inherits can.List
@parent canjs
@download can/model
@test can/model/qunit.html
@description A list connected to can.Model's CRUD abilities.
@signature `new can.Model.List()`
Create an empty model list.
@signature `new can.Model.List( [models] )`
Create a model list with the provided model instances.
@param {Array.<can.Model|Object>} [models] An array of [can.Model] instances
or Objects that will be converted to the list's [can.List.Map Map type].
@signature `new can.Model.List( deferred )`
Create a model list with the results of `deferred`.
@param {Deferred.Array.<can.Model|Object>} deferred A promise that will
resolve to an array. Once the promise resolves, the `List` will have its
contents replaced as if `new can.Model.List(array)` had been called.
@signature `new can.Model.List( params )`
Create an initially empty model list, but use the model's [can.Model.findAll findAll]
to get a list of models and add it to this empty list.
@param {Object} params Params that are passed to
the [can.List.Map Map property's] [can.Model.findAll findAll] method.
@body
## Use
`can.Model.List` is a [can.List] associated with a [can.Model]. `can.Model.List`s
are just like [can.List] except they have a few super-powers:
- They are returned by [can.Model.findAll findAll].
- They automatically remove "destroyed" items.
- They can retrieve items from the server (similar to `findAll`).
## Defining a model list
When [can.Model] is extended, `can.Model.List` is automatically extended and set as that model's
[can.Model.static.List List property]. Typically, a `can.Model.List` is
defined for you. For example:
Task = can.Model.extend({
findAll: "/tasks"
},{})
new Task.List instanceof can.Model.List //-> true
This List type is returned by [can.Model.findAll findAll]:
Task.findAll({}, function(tasks){
tasks instanceof Task.List //-> true
})
The List's [can.List.Map Map] property points to the extended [can.Model]:
Task = can.Model.extend({
findAll: "/tasks"
},{});
Task.List.Map //-> Task
Defining custom `can.Model.Lists` allows you to extend lists with helper
functions for a list of a specific type. The following
adds the ability to retrieve the number of completed and remaining todos:
Todo.List = Todo.List.extend({
completed: function() {
var completed = 0;
this.each(function(i, todo) {
completed += todo.attr('complete') ? 1 : 0
})
return completed;
},
remaining: function() {
return this.attr('length') - this.completed();
}
})
Todo.findAll({}, function(todos) {
todos.completed() // -> 0
todos.remaining() // -> 2
});
## Creating a model list instance
If you use [can.Model.findAll findAll], it calls back with and resolves to a model list:
var def = Task.findAll({}, function(tasks){
tasks instanceof Task.List //-> true
});
def.then(function(tasks){
tasks instanceof Task.List //-> true
})
To create an empty model list yourself, use `new {model_name}.List()` like:
var todos = new Todo.List();
todos.attr("length") //-> 0
You can also pass an array to instantiate the list with the array data using
`new {model_name}.List(ARRAY)`. It can be either an array of models:
var todo1 = new Todo( { name: "Do the dishes", id: 1 } ),
todo2 = new Todo( { name: "Wash floors", id: 2 } )
var todos = new Todo.List( [todo1, todo2] );
...or an array of objects. If objects are provided, model list will convert
them to models. The following does the same thing as the previous example:
var todos = new Todo.List( [
{ name: "Do the dishes", id: 1 },
{ name: "Wash floors", id: 2 }
] );
If, instead of using an array, a model list is created with a plain
JavaScript object like:
var todos = new Todo.List({due: "today"});
The object is assumed to be
parameters to the list's Model's [can.Model.findAll findAll]
method. An empty list will be returned, but `Todo.findAll` will
be called. The items it returns will be inserted into the
list.
var todos = new Todo.List({due: "today"});
todos.attr("length") //-> 0
todos.bind("length", function(){
console.log("items added to the list")
})
## Removing models from model list
One advantage that `can.Model.List` has over a traditional `can.List`
is that when you destroy a model, if it is in that list, it will automatically
be removed from the list.
// Listen for when something is removed from the todos list.
todos.bind("remove", function( ev, oldVals, indx ) {
console.log("todo"+indx+" removed")
})
todos.attr(0).destroy(); // console shows "todo 0 removed"