Knockout.js adding/deleting table lines

This table shows adding deleting items from a table. Items

by CodeRenaissance

HTML

<script src="http://cloud.github.com/downloads/coderenaissance/knockout.mapping/knockout-1.3.0beta.js"></script>
<script src="http://cloud.github.com/downloads/coderenaissance/knockout.mapping/knockout.mapping.js"></script>
<div id="container">
    <div>Note: items that were part of the original data are not deleted, only flagged as deleted.</div>
    <div> Items to update: <span data-bind="text:items().length"/></div>
    <table>
        <thead>
            <tr>
                <td> col1 </td>
                <td> col2 </td>
                <td> col3 </td>
                <td><input type="button" title="add new item" data-bind="click:$root.actions.addItem" value="+"/></td>
            </tr>
        </thead>
        <tbody data-bind="foreach:visibleItems">
            <tr>
                <td><input data-bind="value:$data.c1"/></td>
                <td><input data-bind="value:$data.c2"/></td>
                <td><input data-bind="value:$data.c3"/></td>
                <td><input type="button" title="delete item" data-bind="click:function(){$root.actions.deleteItem($data);}" value="X"/></td>
            </tr>
        </tbody>
    </table>
</div>

CSS

#container table{
    width:300px;
}

#container input{
     width:50px;   
}

#container td{
    padding: 2px 10px;   
}

#container thead td{
    cursor: pointer;
    background:#ccc;   
}

JavaScript

var model= {//this code is injected into the page on the server or retrieved via ajax
    items: [
        { id:"21EC2020-3AEA-1069-A2DD-08002B30309E", c1: "d", c2: "210", c3: "1005", isDeleted:false},
        { id:"C3EC2020-3AEA-1069-A2DD-08002B303094", c1: "z", c2: "1", c3: "205", isDeleted:false},
        { id:"DDEC2020-3AEA-1069-A2DD-08002B30309D", c1: "a", c2: "20", c3: "2005", isDeleted:false}
    ]
};

var viewModel = ko.mapping.fromJS(model);//create a knockout viewModel

viewModel.visibleItems = ko.dependentObservable({
    read: function readVisibleItems(){
        //note the parens after Items because its an observableArray
        return $.map(viewModel.items(), function(item){
            //note the parens after isDeleted because its observable
            return !item.isDeleted() ? item : null;
        });
    },
    owner:viewModel
});

//add actions to your model    
viewModel.actions = {
    addItem:function(){
        //fromJS maps turns all properties into observables
        var newItem = ko.mapping.fromJS({id:null, c1: "", c2: "", c3: "", isDeleted:false})

        viewModel.items.push(newItem);
    },
    deleteItem:function(item){
        var deleteIndex;
        //ensure a visible line always exists
        if(viewModel.visibleItems().length == 1){
            viewModel.actions.addItem();
        }
        
        //note items that were sent down from server have isExisting set to true
        //and must be deleted at the server, however items that were created locally
        //can be deleted locally
        if(!item.id()){//locally create items don't have an id
            deletedIndex = viewModel.items.indexOf(item);
            //assign new array to items, minus the deleted item
            viewModel.items($.map(viewModel.items(), function (element, index) {
                return index === deletedIndex ? null : element;
            }));
        }
        else{
            item.isDeleted(true);
        }
    }
};

//bind viewModel to...