Model顶层负责程序的数据层,使用它可以很容易做以下操作:
1、通过服务端获取和修改数据。
2、监听数据的变化
3、在HTML元素上设置和获取Model
4、分配数组数据
5、其它好东西
Model继承于Class,并且使用REST服务和延迟,所以这些概念是很值得研究的。
1、通过服务端获取和修改数据
Model让连接一个JSON REST服务非常容易。下述的Todo的Model,它具有创建,获取,修改和删除的功能。
$.Model('Todo',{ findAll: 'GET /todos.json', findOne: 'GET /todos/{id}.json', create: 'POST /todos.json', update: 'PUT /todos/{id}.json', destroy: 'DELETE /todos/{id}.json' },{});
这很符合创建,检索,修改和修改的程序设计学。
创建
创建一个Todo对象,通过调用save函数可以在服务端创建Todo。
// create a todo instance var todo = new Todo({name: "do the dishes"}) // save it on the server todo.save();
检索
通过调用findAll函数从服务端检索回一个Todo列表。
Todo.findAll({}, function( todos ){ // print out the todo names $.each(todos, function(i, todo){ console.log( todo.name ); }); });
通过调用findOne函数从服务检索回单个Todo。
Todo.findOne({id: 5}, function( todo ){ // print out the todo name console.log( todo.name ); });
修改
一但有一条记录已经在服务器上创建成功,你就可以通过调用save函数来实现服务端的修改。
// update the todos' name todo.attr('name','Take out the trash') // update it on the server todo.save()
删除
调用destroy函数可以删除服务端的一条记录。
todo.destroy()
监听数据层的变化
监听数据层的变化是MVC结构中的一个关键部分。
Model实现可以监听数据记录的创建,修改,删除,或者记录的属性变化。 Model.bind可以监听一个数据模型的所有事件。 model.bind监听的是一个特定的数据模型实例的事件。
创建
// listen for when any todo is created Todo.bind('created', function( ev, todo ) {...}) // listen for when a specific todo is created var todo = new Todo({name: 'do dishes'}) todo.bind('created', function( ev ) {...})
修改
// listen for when any todo is updated Todo.bind('updated', function( ev, todo ) {...}) // listen for when a specific todo is created Todo.findOne({id: 6}, function( todo ) { todo.bind('updated', function( ev ) {...}) })
删除
// listen for when any todo is destroyed Todo.bind('destroyed', function( ev, todo ) {...}) // listen for when a specific todo is destroyed todo.bind('destroyed', function( ev ) {...})
监听属性变化
// listen for when the name property changes todo.bind('name', function(ev){ })
在控制器中监听
数据层的数据变化监听还可以在控制器中实现监听,你可以使用控制器来监听模型的变化:
$.Controller('Todos',{ "{Todo} updated" : function(Todo, ev, todo) {...} })
注:我们更常用在控制器中监听模型的变化,因为我们这里要实现MVC结构,也就是当模型变化时, 视图也要更新,所以在控制器中监听更常见。
在HTML元素上设置和获取数据
几乎所有,我们都是使用HTML元素给用户显示数据。当数据变化时,我们需要在这些HTML元素反射给数据的变化, 其实就是需要当数据变化时,对应的HTML元素需要更新。
Model提供助手方法很容易可以实现把单个数据模型添加到单个元素上。 当然,也可以把一个模型添加到检索到的所有元素上。
考虑一下,如果一个Todo数据列表以列表元素显示在页面上,当一条Todo数据被删除后,页面上的列表上对应元素删除掉。
$.fn.model(item) 函数提供一个HTML元素设置或者读取一个模型实例:
Todo.findAll({}, function( todos ) { $.each(todos, function(todo) { $('<li>').model(todo) .text(todo.name) .appendTo('#todos') }); });
当一个Todo删除后,使用item.elements获取对应的HTML元素,并且从页面上移除它。
//执行模型的删除动作后 todo.destroy(); //触发这个事件 Todo.bind('destroyed', function( ev, todo ) { todo.elements( $('#todos') ).remove() })
使用EJS和控制器
使用View和EJS非常容易给元素添加模型数据。下述我们实现的是Todos控件:
$.Controller('Todos',{ init: function(){ this.element.html('//todos/views/todos.ejs', Todo.findAll({}) ); }, "{Todo} destroyed": function(Todo, ev, todo) { todo.elements( this.element ).remove() } })
在todos.ejs:
<% for(var i =0; i < todos.length; i++){ %> <li <%= todos[i] %> ><%= todos[i].name %></li> <% } %>
提示:我们是通过<%= model %>
给每个元素添加模型的。有时候我们也会发现添加
todo todo_0,可是在页面操作的时候没有起作用, 那可能你又给这个元素添加了其它东西,把Model移除了。例如:我们使用其它的UI对元素渲染,是最常见的一种情况。
列模型
Model.List可以操作多个模型实例。列相似于一个数组,它只是添加了一些特别的属性和监听事件。 Model.List是一个独立的插件。如果想了解Model.List,请阅读《JavaScriptMVC之Fixture续》
其它好东西
Model让一些其它常见工作更加容易:
1、数据类型的转换
常常,你们需要把数据的转换成更有效的数据类型。
详细请阅读《JavaScriptMVC之数据处理》
2、关联
属性也提供了关联。例如,todo数据中可能带有一个owner属性,而这个属性是一个User数据模型。
{ name: 'take out trash', id: 1, owner: { name: 'Justin', id: 3} }
如果想把owner转换成User模型,设置这个owner的类型为User的model方法:
$.Model('Todo',{ attributes : { owner: 'User.model' } },{})
3、助手函数
常常,你需要去执行一个模型数据的重复计算操作。你可以在模型的原型中创建方法,它将在所有模型的实例中有效。
下述创建一个剩余时间方法,它返回的是秒的数值:
$.Model('Todo',{ },{ timeRemaining : function(){ return new Date() - new Date(this.dueDate) } }) // create a todo var todo = new Todo({dueDate: new Date()}); // show off timeRemaining todo.timeRemaining() //-> Number
4、延迟
Model方法发送请求到服务端如:findAll,findOne,save,和destroy。它返回一个延迟对象,延迟对象是解决数据项是否已经检索或者修改。 延迟实现异步代码非常容易。例如,下述是等待所有用户列表和任务列表返回:
$.when(Task.findAll(), User.findAll()) .then(function( tasksRes, usersRes ){ ... })
5、验证
验证模型的属性值
$.Model("Contact",{ init : function(){ this.validate("birthday",function(){ if(this.birthday > new Date){ return "your birthday needs to be in the past" } }) } ,{});
详细请阅读《JavaScriptMVC之数据处理》
6、备份和还原
Model本身没有带这个功能,为什么在这里也会写这个功能呢?
是因为这个功能,在我们开发过程中遇到,所以在这里也列出来。
需要使用这个功能,我们得引入这个插件jquery/model/backup。
这个插件提供了3个函数,备份(backup),数据是否修改(isDirty)和还原(restore);
假设以下场景:
我们创建或者修改一个数据,要求:
1、如果没有修改,那么我们就不要提交到后台。
2、如果已经修改,但是我们要离开这个修改页面,用户还没有保存数据,提示用户是否要保存。
3、如果修改过程,我们想还原到原来的数据。
如果碰到上面的情况,那么这个备份和还原就非常有用。
使用备份/还原
1、在使用数据模型实例之前,先备份:
var recipe = new Recipe({name: "cheese"}); recipe.backup()
2、判断模型实例是否已经被修改:
recipe.name = 'blah' recipe.isDirty() //-> true
3、最后,还原数据:
recipe.restore(); recipe.name //-> "cheese"