Knockout.JS Tutorials

Loading and Saving Data

by Marventus

HTML

<script src="https://cdnjs.cloudflare.com/ajax/libs/knockout/3.3.0/knockout-debug.js"></script>
<link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.4/css/bootstrap.min.css">
<link rel="stylesheet" href="https://ajax.googleapis.com/ajax/libs/jqueryui/1.11.4/themes/smoothness/jquery-ui.css">
<script src="https://ajax.googleapis.com/ajax/libs/jqueryui/1.11.4/jquery-ui.min.js"></script>
<script src="https://jquery-star-rating-plugin.googlecode.com/svn/trunk/jquery.rating.js"></script>
<link rel="stylesheet" href="https://jquery-star-rating-plugin.googlecode.com/svn/trunk/jquery.rating.css">
<link rel="stylesheet" href="http://learn.knockoutjs.com/Content/TutorialSpecific/custombindings.css">
<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>

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

JavaScript

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

function TaskListViewModel() {
    // Data
    var self = this;
    self.data = '[{"title":"Wire the money to Panama","isDone":true},{"title":"Get hair dye, beard trimmer, dark glasses and \"passport\"","isDone":false},{"title":"Book taxi to airport","isDone":false},{"title":"Arrange for someone to look after the cat","isDone":false}]';
    self.tasks = ko.observableArray([]);
    self.newTaskText = ko.observable();
    self.incompleteTasks = ko.computed(function() {
        return ko.utils.arrayFilter(self.tasks(), function(task) { return !task.isDone() && !task._destroy });
    });

    // Operations
    self.addTask = function() {
        self.tasks.push(new Task({ title: this.newTaskText() }));
        self.newTaskText("");
    };
    self.removeTask = function(task) {
        self.tasks.destroy(task);
        console.log(self.tasks());
    };
    self.save = function() {
        $.ajax(self.ajaxUrl, {
            data: ko.toJSON({ tasks: self.tasks }),
            type: "post", contentType: "application/json",
            success: function(result) { alert(result) }
        });
    };

    // Load initial state from server, convert it to Task instances, then populate self.tasks
    self.load = function = (allData) {
        var mappedTasks = $.map(allData, function(item) { return new Task(item) });
        self.tasks(mappedTasks);
    });    
}

ko.applyBindings(new TaskListViewModel());