【问题标题】:Widget binding with Gridster and Knockout使用 Gridster 和 Knockout 绑定小部件
【发布时间】:2013-11-02 04:02:10
【问题描述】:

我是 Javascript 新手,正在尝试将 Gridster 与 Knockout 一起使用。我有一个包含项目的数据库,我使用淘汰赛 foreach 将它们绑定到 UL。 UL 使用 Gridster 库进行样式设置。除非我尝试通过视图模型中的 ObservableArray 向 UL 添加其他元素,否则一切都很好。

谁能帮我理解这里的操作范围和顺序?感觉 Gridster 库并没有对新的小部件进行样式设置。

This jsfiddle 显示了该问题的工作演示。请注意,当您双击一个小部件时,它会创建一个新小部件,但不会将其放置在网格中。相反,它只是在后面闲逛。

这里是 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>

这里是 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]
});

【问题讨论】:

  • 我用一些额外的代码更新了 JSFiddle,这些代码可以手动将小部件添加到 gridster... 东西。据我所知,它有效,但我仍然不确定为什么和/或如何。 jsfiddle.net/Y5swe/3
  • 我在这方面又取得了一些进展。看起来 Gridster 对 Knockout 添加元素一无所知。我现在唯一的建议是手动添加它们。这是最新的小提琴。 jsfiddle.net/Y5swe/13

标签: javascript jquery knockout.js gridster


【解决方案1】:

这是JSfiddle 中的完整示例。在这里,我只强调了删除功能

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);                
        });
    }
};

从 observable 数组中移除元素的工作是在 remove_widget 回调中完成的。请参阅 gridster 的documentation。因此,在删除小部件之前执行的 removeGridster 钩子不再需要执行实际的 remove_widget 调用。

【讨论】:

  • 小提琴很棒!它节省了我很多时间来解决这个问题。我唯一的问题是,如果您在 $() 中初始化 gridster 而不是使用 afterRender 模板,为什么它不起作用?
  • 另外,我发现了一个限制:无论你在 addOne 函数中为添加的小部件的 x 和 y 指定什么大小,它都是 1x1。
  • 可以通过在 self.addGridster 函数中调用 add_wiget 之前移动 obj.datacol = parseInt(column);obj.datarow = parseInt(widget.attr("data-row")); 行来缓解 1x1 限制。还在同一个 add_widget 调用之前添加以下行:obj.datasizex = parseInt(widget.attr("data-sizex"));` 和 obj.datasizey = parseInt(widget.attr("data-sizey"));@ 987654329@widget.data('col')` 而不是widget.attr('data-col')
【解决方案2】:

这是一个我认为更符合 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);

我仍然需要考虑删除和移动事件(gridster 中的移动应该更新视图模型中项目的 x 和 y 值)。我昨天开始使用淘汰赛,所以任何帮助将不胜感激。

我找不到最新版本的 gridster 的 CDN。 JSFiddle 指向我在 Azure 中添加的一个临时网站,我会保留几天,但请随时使用您自己的链接对其进行更新。

/----------------- 更新 --------------- -------------------/

我已更新我的代码以支持删除和移动小部件 (http://jsfiddle.net/Be4cf/11/),但有一个小警告:存在一个未解决的问题 (https://github.com/knockout/knockout/issues/1130),即在调用 beforeRemove 事件之前,敲除会清除 jquery 数据。这会导致 gridster 崩溃,因为移动其他项目所需的数据保存在数据元素中。一种解决方法可能是保留数据的副本并稍后将其重新添加到元素中,但我选择了惰性方式并在淘汰赛中评论了违规行。

【讨论】:

  • 您的解决方案不完整。如果您想将 Widget 添加到特定的行和列中会发生什么?我认为您没有意识到 Gridster 不会监视 DOM 元素的更改。一旦你理解了这一点,你就会明白为什么调用add_widget 是必要的——你最初是在更新 DOM 元素而没有通知 Gridster。如果我是你,我会摆脱 KnockoutJS 视图 (.html),走上通过 Gridster API 方法做所有事情的路线。
【解决方案3】:

将 class="gs_w" 添加到 gridster 中的你的 li 应该可以工作

【讨论】:

  • 感谢您的帮助,但这不起作用。你可以在这个 jsfiddle 上自己尝试这个建议...jsfiddle.net/Y5swe/13
【解决方案4】:

您应该执行以下操作。 addNewGridElement 被调用 - 渲染的 DOM 元素在 Gridster 的情况下很重要,因为 gridster.add_widget 接受一个 DOM 元素作为它的第一个参数 - 一旦你向 Knockout observable 添加了一些东西。在此之后,只需将domNode 添加到 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);
    }
};

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2012-02-24
    • 2016-09-10
    • 1970-01-01
    • 1970-01-01
    • 2019-04-25
    • 2013-06-02
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多