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...