Knockout - MVVM basics - function

HTML

<link rel="stylesheet" href="http://www.rabblesoft.com/sites/haroon/gridster/dist/jquery.gridster.css">
<script src="http://testgridster.azurewebsites.net/gridster.js"></script>
<script src="http://ajax.aspnetcdn.com/ajax/knockout/knockout-3.0.0.js"></script>
<div class="gridster" data-bind="template: {afterRender: initializeGridster}">
    <ul class="layouts_grid2" data-bind="foreach: myData">
        <li data-bind="attr:{'id': id, 'data-row':datarow, 'data-col':datacol, 'data-sizex':datasizex, 'data-sizey':datasizey}, template: {afterRender: $root.addGridster} ">
            <span data-bind="text: text"/>
        </li>
    </ul>
    <button data-bind="click: addOne">Add</button> <!-- I plugged the add event on a button for simplicity -->
</div>

CSS

/*! gridster.js - v0.1.0 - 2012-10-20
* http://gridster.net/
* Copyright (c) 2012 ducksboard; Licensed MIT */
 body {
    background-color: #011529;
}
li {
    background-color: #FFFFFF;
    list-style: none;
}
widget {
    background-color: #bcddfe;
}
/*! gridster.js - v0.2.1 - 2013-10-28
* http://gridster.net/
* Copyright (c) 2013 ducksboard; Licensed MIT */

.gridster {
    position:relative;
}

.gridster > * {
    margin: 0 auto;
    -webkit-transition: height .4s;
    -moz-transition: height .4s;
    -o-transition: height .4s;
    -ms-transition: height .4s;
    transition: height .4s;
}

.gridster .gs-w {
    z-index: 2;
    position: absolute;
}

.ready .gs-w:not(.preview-holder) {
    -webkit-transition: opacity .3s, left .3s, top .3s;
    -moz-transition: opacity .3s, left .3s, top .3s;
    -o-transition: opacity .3s, left .3s, top .3s;
    transition: opacity .3s, left .3s, top .3s;
}

.ready .gs-w:not(.preview-holder),
.ready .resize-preview-holder {
    -webkit-transition: opacity .3s, left .3s, top .3s, width .3s, height .3s;
    -moz-transition: opacity .3s, left .3s, top .3s, width .3s, height .3s;
    -o-transition: opacity .3s, left .3s, top .3s, width .3s, height .3s;
    transition: opacity .3s, left .3s, top .3s, width .3s, height .3s;
}

.gridster .preview-holder {
    z-index: 1;
    position: absolute;
    background-color: #fff;
    border-color: #fff;
    opacity: 0.3;
}

.gridster .player-revert {
    z-index: 10!important;
    -webkit-transition: left .3s, top .3s!important;
    -moz-transition: left .3s, top .3s!important;
    -o-transition: left .3s, top .3s!important;
    transition:  left .3s, top .3s!important;
}

.gridster .dragging,
.gridster .resizing {
    z-index: 10!important;
    -webkit-transition: all 0s !important;
    -moz-transition: all 0s !important;
    -o-transition: all 0s !important;
    transition: all 0s !important;
}


.gs-resize-handle {
    position: absolute;
    z-index: 1;
}

.gs-resize-handle-both {
   ...

JavaScript

//This is some widget data to start the process
var gridData = [
    {id: "1", text:'Widget #1', datarow:1, datacol:1, datasizex:1, datasizey:1},
    {id: "2", text:'Widget #2', datarow:1, datacol:2, datasizex:2, datasizey:1},
    {id: "3", text:'Widget #3', datarow:1, datacol:4, datasizex:1, datasizey:1},
    {id: "4", text:'Widget #4', datarow:2, datacol:1, datasizex:1, datasizey:2}];

// The viewmodel contains an observable array of widget data to be 
//    displayed on the gridster
var viewmodel = function () {

    var self = this;
    self.myData = ko.observableArray(gridData);
    self.nextId = 5;
    self.gridster = undefined;
    
    // AddOne adds an element to the observable array.
    // Notice how I'm not adding the element to gridster by hand here. This means that whatever
    // the source of the add (click, callback, web sockets event), the element will be added to gridster.
    self.addOne = function () {
                myViewModel.myData.push({
            text: 'Widget Added After!',
            datarow: 1,
            datacol: 1,
            datasizex: 1,
            datasizey: 1,
            id: self.nextId++
        });
    };
    
    // Called after the render of the initial list.
    // Gridster will add the existing widgets to its internal model.
    self.initializeGridster = function() {
        self.gridster = $(".gridster ul").gridster({
            widget_margins: [5, 5],
            widget_base_dimensions: [140, 140]
        }).data('gridster');
    };
    
    // Called after the render of the new element.
    self.addGridster = function(data, object) {
        // This bypasses the add if gridster has not been initialized.
        if (self.gridster) {
            var $item = $(data[0].parentNode);
            
            // The first afterRender event is fired 2 times. It appears to be a bug in knockout.
            // I'm pretty new to knockout myself, so it might be a feature too! :)
            // This skips the second call...