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.save3,客户端删除数据更新,你并不需要通过和数据库的数据必须比较来了发现客户端删除了哪些数据。当操作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"> </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());
ko.bindingHandlers.fadeVisible = { init: function(element, valueAccessor) { // Start visible/invisible according to initial value var shouldDisplay = valueAccessor(); $(element).toggle(shouldDisplay); }, update: function(element, valueAccessor) { // On update, fade in/out var shouldDisplay = valueAccessor(); shouldDisplay ? $(element).fadeIn() : $(element).fadeOut(); } };
<h3 data-bind="fadeVisible: pointsUsed() > pointsBudget">You've used too many points! Please remove some.</h3>