learn.knockoutjs.com - Loading and saving data

http://learn.knockoutjs.com/#/?tutorial=loadingsaving

by olli

HTML

<script src="http://learn.knockoutjs.com/Scripts/Lib/jquery.tmpl.js"></script>
<script src="http://learn.knockoutjs.com/Scripts/Lib/jquery.address.js"></script>
<script src="http://learn.knockoutjs.com/Scripts/Lib/knockout-1.3.0.latest.js"></script>
<link rel="stylesheet" href="http://code.jquery.com/mobile/1.0rc2/jquery.mobile-1.0rc2.min.css">
<script src="http://code.jquery.com/mobile/1.0rc2/jquery.mobile-1.0rc2.min.js"></script>
<body class="codeRunner">
    <div data-role="page" id="mypage">
        <div data-role="header">
            <h1>
                Tutorial 5
            </h1>
        </div>
        <div data-role="content">
            <h3>Tasks</h3>
            
            <div data-role="fieldcontain">
                <label for="newTask">Add task</label>
                <input id="newTask" data-bind="value: newTaskText" placeholder="What needs to be done?" />
            </div>
            <button data-bind="click: addTask">Add</button>
            <br/>
            
            
            <ul id="taskList" data-role="listview" data-inset="true" data-bind="template: { name: 'taskTemplate', foreach: tasks, afterAdd: function() {$('#taskList').listview('refresh'); } }, visible: tasks().length > 0"></ul>
            <script type="text/html" id="taskTemplate">
                <li>
                    <a data-bind="click: editItem">
                        <span data-bind="text: title"></span>
                        <span data-bind="visible: isDone()" class="ui-li-count">done</span>
                    </a>
                    
                </li>
            </script>
            
            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>
            
            
            
        </div>
    </div>
    
    <div data-role="page"...

JavaScript

$(function() {

    function task(title, isDone, ownerViewModel) {
        this.title = ko.observable(title);
        this.isDone = ko.observable(isDone);
        this.remove = function() {
            ownerViewModel.tasks.destroy(this);
        };
        this.editItem = function() {
            console.log(ownerViewModel.tasks.indexOf(this));
            console.log('editItem');
            $.mobile.changePage( "#editItem", { role: "dialog"} );    
        };
    }

    function taskListViewModel() {
        this.tasks = ko.observableArray([]);
        this.newTaskText = ko.observable();
        this.addTask = function() {
            this.tasks.push(new task(this.newTaskText(), false, this));
            this.newTaskText("");
        }
        this.incompleteTasks = ko.dependentObservable(function() {
            return ko.utils.arrayFilter(this.tasks(), function(task) {
                return !task.isDone() && !task._destroy;
            });
        }, this);

        // Load initial state from server
        var self = this;
        $.ajax("/echo/json/", {
            data: {
                json: ko.toJSON(fakeData)
            },
            type: "POST",
            dataType: 'json',
            success: function(data) {
                var mappedTasks = $.map(data, function(item) {
                    return new task(item.title, item.isDone, self);
                });
                self.tasks(mappedTasks);
            }
        });

        this.save = function() {
            $.ajax("/echo/json/", {
                data: {
                    json: ko.toJSON({
                        tasks: this.tasks
                    })
                },
                type: "POST",
                dataType: 'json',
                success: function(result) {
                    alert(ko.toJSON(result))
                }
            });
        }
    }


    ko.applyBindings(new taskListViewModel());

});


var fakeData = [{
    "title": "Wire the money to...