<!DOCTYPE html> <html lang="en"> <head> <!--[if lt IE 9]> <script src="http://html5shim.googlecode.com/svn/trunk/html5.js"></script> <![endif]--> <meta charset="utf-8"> <meta http-equiv="X-UA-Compatible" content="IE=edge"> <meta name="viewport" content="width=device-width, initial-scale=1"> <title>Knockout.js demo</title> <link rel="stylesheet" href="//maxcdn.bootstrapcdn.com/bootstrap/3.2.0/css/bootstrap.min.css"> <link rel="stylesheet" href="//cdnjs.cloudflare.com/ajax/libs/font-awesome/4.2.0/css/font-awesome.min.css"/> <link rel="stylesheet" href="../dist/gridstack.css"/> <script src="//ajax.googleapis.com/ajax/libs/jquery/1.11.1/jquery.min.js"></script> <script src="//cdnjs.cloudflare.com/ajax/libs/jqueryui/1.11.0/jquery-ui.js"></script> <script src="//maxcdn.bootstrapcdn.com/bootstrap/3.2.0/js/bootstrap.min.js"></script> <script src="//cdnjs.cloudflare.com/ajax/libs/lodash.js/3.5.0/lodash.min.js"></script> <script src="//cdnjs.cloudflare.com/ajax/libs/knockout/3.2.0/knockout-min.js"></script> <script src="../dist/gridstack.js"></script> <style type="text/css"> .grid-stack { background: lightgoldenrodyellow; } .grid-stack-item-content { color: #2c3e50; text-align: center; background-color: #18bc9c; } </style> </head> <body> <div class="container-fluid"> <h1>knockout.js Demo</h1> <div> <button data-bind="click: add_new_widget">Add new widget</button> </div> <br> <div data-bind="component: {name: 'dashboard-grid', params: $data}"></div> </div> <script type="text/javascript"> ko.components.register('dashboard-grid', { viewModel: { createViewModel: function (controller, componentInfo) { var ViewModel = function (controller, componentInfo) { var grid = null; this.widgets = controller.widgets; this.afterAddWidget = function (items) { if (grid == null) { grid = $(componentInfo.element).find('.grid-stack').gridstack({ auto: false }).data('gridstack'); } var item = _.find(items, function (i) { return i.nodeType == 1 }); grid.add_widget(item); ko.utils.domNodeDisposal.addDisposeCallback(item, function () { grid.remove_widget(item); }); }; }; return new ViewModel(controller, componentInfo); } }, template: [ '<div class="grid-stack" data-bind="foreach: {data: widgets, afterRender: afterAddWidget}">', ' <div class="grid-stack-item" data-bind="attr: {\'data-gs-x\': $data.x, \'data-gs-y\': $data.y, \'data-gs-width\': $data.width, \'data-gs-height\': $data.height, \'data-gs-auto-position\': $data.auto_position}">', ' <div class="grid-stack-item-content"><button data-bind="click: $root.delete_widget">Delete me</button></div>', ' </div>', '</div> ' ].join('') }); $(function () { var Controller = function (widgets) { var self = this; this.widgets = ko.observableArray(widgets); this.add_new_widget = function () { this.widgets.push({ x: 0, y: 0, width: Math.floor(1 + 3 * Math.random()), height: Math.floor(1 + 3 * Math.random()), auto_position: true }); }; this.delete_widget = function (item) { self.widgets.remove(item); }; }; var widgets = [ {x: 0, y: 0, width: 2, height: 2}, {x: 2, y: 0, width: 4, height: 2}, {x: 6, y: 0, width: 2, height: 4}, {x: 1, y: 2, width: 4, height: 2} ]; var controller = new Controller(widgets); ko.applyBindings(controller); }); </script> </body> </html>