日期:2014-05-16  浏览次数:20406 次

knockoutjs -- load save data(与服务器进行数据交互) & binding绑定
和服务器交互数据:
Knockout 是一纯javascript库,它可以与任何能发送和接收JSON数据的服务器进行交互。

从服务器取得数据:使用$.getJSON或者$.ajax从服务器端取得JSON数据,然后更新viewmodel。注意:你并不是在服务器下载完数据后才执行ko.applyBindings操作。不需要在从服务器下载数据完毕后重新进行绑定操作,因为当数据下载完毕后,Knockout 会自动根据viewmodel的状态来更新相应的UI.

提交数据到服务器:
  • 方法1,简单地使用Html from控件,在控件内部放要提交到服务器的JSON的值(放一个隐藏域,其值通过toJSON方法取到,data-bind="value: ko.toJSON(tasks)"),然后再放置一个Submit按钮。如下:type="submit"
  • 方法2,使用ajax方法,提交需要的数据给服务器,然后服务器处理。如下:self.save
  • 3,客户端删除数据更新,你并不需要通过和数据库的数据必须比较来了发现客户端删除了哪些数据。当操作observable数组的时候,不使用self.tasks.remove(task)来直接删除数据,而是使用self.tasks.destroy(task)。destroy方法并不真正删除数据,而是在数据中增加_destroy属性(foreach会自动根据_destroy属性而不显示被删除记录),然后提交到服务器后,服务器端解析_destroy就能知道客户端用户请求删除哪些数据。使用destroy方法后,原来的统计数字不正确了,修改统计方法,增加&& !task._destroy判断。

<h3>Tasks</h3>

<form data-bind="submit: addTask">
    Add task: <input data-bind="value: newTaskText" placeholder="What needs to be done?" />
    <button type="submit">Add</button>
</form>

<ul data-bind="foreach: tasks, visible: tasks().length > 0">
    <li>
        <input type="checkbox" data-bind="checked: isDone" />
        <input data-bind="value: title, disable: isDone" />
        <a href="#" data-bind="click: $parent.removeTask">Delete</a>
    </li>
</ul>

You have <b data-bind="text: incompleteTasks().length">&nbsp;</b> incomplete task(s)
<span data-bind="visible: incompleteTasks().length == 0"> - it's beer time!</span>

<form action="/tasks/saveform" method="post">
    <textarea name="tasks" data-bind="value: ko.toJSON(tasks)"></textarea>
    <input type="hidden" name="tasks" type="hidden" data-bind="value: ko.toJSON(tasks)" />
    <button type="submit">Save</button>
</form>

<button data-bind="click: save">Save</button>

function Task(data) {
    this.title = ko.observable(data.title);
    this.isDone = ko.observable(data.isDone);
}

function TaskListViewModel() {
    // Data
    var self = this;
    self.tasks = ko.observableArray([]);
    self.newTaskText = ko.observable();
    self.incompleteTasks = ko.computed(function() {
        return ko.utils.arrayFilter(self.tasks(), function(task) { return !task.isDone() });
    });

    // Operations
    self.addTask = function() {
        self.tasks.push(new Task({ title: this.newTaskText() }));
        self.newTaskText("");
    };
    // self.removeTask = function(task) { self.tasks.remove(task) };
    self.removeTask = function(task) { self.tasks.destroy(task) };
    
    // Load initial state from server, convert it to Task instances, then populate self.tasks
    $.getJSON("/tasks", function(allData) {
        var mappedTasks = $.map(allData, function(item) { return new Task(item) });
        self.tasks(mappedTasks);
    });    
    
    self.save = function() {
        $.ajax("/tasks", {
            data: ko.toJSON({ tasks: self.tasks }),
            type: "post", contentType: "application/json",
            success: function(result) { alert(result) }
        });
    };
}

ko.applyBindings(new TaskListViewModel());


绑定:
在MVVM解释器中,bindings绑定是把用户的视图view和viewmodel关联起来,bindings就是中间人,它执行双向更新:
  • binding发现viewmodel 发生变化,然后更新相应的view的DOM
  • binding捕获DOM events事件,然后更新viewmodel的属性

Knockout 有一个灵活的,综合的内置绑定集合(包含如text, click, foreach等),同时你也可以使用少量代码来完成自定义的bindings 。
自定义binding
1,给ko.bindingHandlers增加新的绑定属性,然后实现下面2个回调方法
2,init:在绑定刚开始的时候被调用,一般用来设置初始状态或者注册事件处理器
3,update:当关联的data发生变化的时候被调用,一般用来更新data相应的DOM
自定义fade binding例子: