template packery gridstack examples bootstrap addwidget javascript jquery knockout.js gridster

javascript - gridstack - jquery packery



Widget vinculante con Gridster y Knockout (4)

Soy nuevo en Javascript y trato de usar Gridster con Knockout. Tengo una base de datos con elementos, y utilizo foreach knockout para vincularlos a un UL. El UL está diseñado con la biblioteca Gridster. Todo funciona muy bien a menos que intente agregar elementos adicionales a UL a través de ObservableArray en el modelo de vista.

¿Alguien puede ayudarme a entender el alcance y el orden de las operaciones aquí? Parece que la biblioteca Gridster no está adaptando su estilo a los nuevos widgets.

Este jsfiddle muestra una demostración funcional del problema. Observe que cuando hace doble clic en un widget, crea uno nuevo pero no lo coloca en la cuadrícula. En cambio, simplemente se queda atrás.

Aquí está el HTML

<div class="gridster"> <ul data-bind="foreach: myData"> <li data-bind="attr:{ ''data-row'':datarow, ''data-col'':datacol, ''data-sizex'':datasizex, ''data-sizey'':datasizey },text:text, doubleClick: $parent.AddOne"></li> </ul> </div>

Aquí está el Javascript

//This is some widget data to start the process var gridData = [ {text:''Widget #1'', datarow:1, datacol:1, datasizex:1, datasizey:1}, {text:''Widget #2'', datarow:2, datacol:1, datasizex:1, datasizey:1}, {text:''Widget #3'', datarow:1, datacol:2, datasizex:1, datasizey:1}, {text:''Widget #4'', datarow:2, datacol:2, datasizex:1, datasizey:1}]; // 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); //AddOne adds an element to the observable array // (called at runtime from doubleClick events) self.AddOne = function () { var self = this; myViewModel.myData.push({ text: ''Widget Added After!'', datarow: 1, datacol: 1, datasizex: 1, datasizey: 1 }); }; }; var myViewModel = new viewmodel(); ko.applyBindings(myViewModel); $(".gridster ul").gridster({ widget_margins: [5, 5], widget_base_dimensions: [140, 140] });


Añada class = "gs_w" a ur li en gridster, debería funcionar


Aquí hay una solución de trabajo que creo que está más en línea con el patrón de MVVM:

http://jsfiddle.net/Be4cf/4/

//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 is (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 from the initial fired event. if (!$item.hasClass("gs-w")) { // This removes the binding from the new node, since gridster will re-add the element. ko.cleanNode(data[0].parentNode); // Adds the widget to gridster. self.gridster.add_widget($item); // We must update the model with the position determined by gridster object.datarow = parseInt($item.attr("data-row")); object.datacol = parseInt($item.attr("data-col")); } } }; }; var myViewModel = new viewmodel(); ko.applyBindings(myViewModel);

Todavía tengo que pensar en los eventos de quitar y mover (un movimiento en gridster debería actualizar los valores xey de los elementos en el modelo de vista). Empecé a usar knockout ayer, por lo que cualquier ayuda sería apreciada.

No pude encontrar un cdn para la última versión de gridster. JSFiddle apunta a un sitio web temporal que agregué en Azure, lo dejaré por unos días, pero no dude en actualizarlo con su propio enlace.

/ ------------------------------ ACTUALIZACIÓN ------------------ ---------------- /

He actualizado mi código para admitir eliminaciones y mover widgets ( http://jsfiddle.net/Be4cf/11/ ) pero hay una pequeña advertencia: hay un problema abierto ( https://github.com/knockout/knockout/issues / 1130 ) que el knockout elimina los datos de jquery antes de llamar al evento beforeRemove. Esto hace que gridster se bloquee ya que los datos necesarios para mover los otros elementos se guardan en un elemento de datos. Una solución alternativa podría ser mantener una copia de los datos y volver a agregarlos al elemento más adelante, pero he elegido la forma perezosa y comenté la línea ofensiva en knockout.


Aquí hay un ejemplo completo en JSfiddle . Aquí, he resaltado solo la función de borrar

self.deleteOne = function (item) { console.log(item); var widget = $("#" + item.id); console.log(widget); var column = widget.attr("data-col"); if (column) { console.log(''Removing ''); // if this is commented out then the widgets won''t re-arrange self.gridster.remove_widget(widget, function(){ self.myData.remove(item); console.log(''Tiles: ''+self.myData().length); }); } };

El trabajo de eliminar el elemento de la matriz observable se realiza dentro de la devolución de llamada remove_widget. Ver la documentación de gridster. En consecuencia, el enlace removeGridster ejecutado antes de eliminar un widget, ya no necesita hacer la llamada remove_widget real.


Deberías hacer algo como a continuación. Se llama addNewGridElement , con el elemento DOM renderizado, que es importante en el caso de gridster.add_widget ya que gridster.add_widget acepta un elemento DOM como primer argumento, una vez que haya agregado algo al observable Knockout. Después de esto, solo se trata de agregar domNode a Gridster.

view.html:

<div class="gridster"> <ul data-bind="foreach: { myData, afterAdd: $root.addNewGridElement }"> <li data-bind="attr:{ ''data-row'':datarow, ''data-col'':datacol, ''data-sizex'':datasizex, ''data-sizey'':datasizey },text:text, doubleClick: $parent.AddOne"></li> </ul> </div>

view.js:

self.addNewGridElement = function (domNode, index, newTile) { // Filter non li items - this will remove comments etc. dom nodes. var liItem = $(domNode).filter(''li''); if ( liItem.length > 0 ) { // Add new Widget to Gridster self.gridster.add_widget(domNode, newTile.x, newTile.y, newTile.row, newTile.col); } };