【问题标题】:Gridstack not updating on deleteGridstack在删除时不更新
【发布时间】:2016-06-07 03:34:21
【问题描述】:

这是我使用 Knockout 绑定的 Gridstack 布局示例。问题是我的视图没有根据模型更新,什么时候应该更新。

按下Delete me 后,控制台输出显示widgets 可观察数组得到正确更新,而视图没有。原因似乎在这条线上(没有被调用):

ko.utils.domNodeDisposal.addDisposeCallback(item, function () { 
    self.grid.removeWidget(item); 
});

据我所知,foreach 绑定应该会自动更新,为什么没有呢?

var ViewModel = function() {
  var self = this;
  self.grid = null;
  self.widgets = ko.observableArray([{
    x: 0,
    y: 0,
    width: 1,
    height: 1
  }, {
    x: 0,
    y: 1,
    width: 1,
    height: 1
  }]);
  self.deleteWidget = function(item) {
    console.log("widgets before", self.widgets());
    self.widgets.remove(item);
    console.log("widgets after", self.widgets());
    return false;
  };
  self.afterAddWidget = function(items) {
    if (self.grid == null) {
      self.grid = $('.grid-stack').gridstack({
        auto: false
      }).data('gridstack');
    }
    var item = _.find(items, function(i) {
      return i.nodeType == 1
    });
    self.grid.addWidget(item);
    ko.utils.domNodeDisposal.addDisposeCallback(item, function() {
      self.grid.removeWidget(item);
    });
  };
};
ko.applyBindings(new ViewModel());
.grid-stack {
  background: lightgoldenrodyellow;
}
.grid-stack-item-content {
  color: #2c3e50;
  text-align: center;
  background-color: #18bc9c;
}
<link rel="stylesheet" href="https://raw.githubusercontent.com/troolee/gridstack.js/master/dist/gridstack.css" />
<script src="//ajax.googleapis.com/ajax/libs/jquery/1.11.1/jquery.min.js" type="text/javascript"></script>
<script src="//cdnjs.cloudflare.com/ajax/libs/jqueryui/1.11.0/jquery-ui.js" type="text/javascript"></script>
<script src="//maxcdn.bootstrapcdn.com/bootstrap/3.2.0/js/bootstrap.min.js" type="text/javascript"></script>
<script src="//cdnjs.cloudflare.com/ajax/libs/lodash.js/3.5.0/lodash.min.js" type="text/javascript"></script>
<script src="//cdnjs.cloudflare.com/ajax/libs/knockout/3.2.0/knockout-min.js" type="text/javascript"></script>
<script type="text/javascript" src="https://rawgit.com/troolee/gridstack.js/master/dist/gridstack.js"></script>

<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.deleteWidget">Delete me</button>
    </div>
  </div>
</div>

【问题讨论】:

    标签: javascript knockout.js foreach gridstack


    【解决方案1】:

    Gridstack 是一个 DOM 控制小部件。您需要某种绑定处理程序来使 Knockout 与 DOM 控制小部件很好地配合使用。

    您似乎在this example 工作。它以某种内置绑定处理程序的方式使用组件。它似乎有效,但我建议将 DOM 操作放在合适的位置:在绑定处理程序中。

    更新:这是您将 gridstack 代码放入绑定处理程序的示例。它只是包装了一个foreach 绑定处理程序,并在更新中将afterRender 选项添加到它。现在视图模型看起来像一个视图模型,您可以在一个页面上处理多个网格堆栈,而不会$(.grid-stack) 选错一个。

    ko.bindingHandlers.gridstack = {
      init: function(element, valueAccessor, allBindingsAccessor, data, context) {
        ko.bindingHandlers.foreach.init(element, valueAccessor, allBindingsAccessor, data, context);
    
        return {
          controlsDescendantBindings: true
        };
      },
      update: function(element, valueAccessor, allBindingsAccessor, data, context) {
        var widgets = valueAccessor(),
          grid = $(element).gridstack().data('gridstack'),
          afterAddWidget = function(items) {
            var item = _.find(items, function(i) {
              return i.nodeType === 1;
            });
            grid.addWidget(item);
            ko.utils.domNodeDisposal.addDisposeCallback(item, function() {
              grid.removeWidget(item);
            });
          },
          newVA = function() {
            return {
              data: widgets,
              afterRender: afterAddWidget
            };
          };
        ko.bindingHandlers.foreach.update(element, newVA, allBindingsAccessor, data, context);
      }
    };
    
    var ViewModel = function() {
      var self = this;
      self.grid = null;
      self.widgets = ko.observableArray([{
        x: 0,
        y: 0,
        width: 1,
        height: 1
      }, {
        x: 0,
        y: 1,
        width: 1,
        height: 1
      }]);
      self.deleteWidget = function(item) {
        self.widgets.remove(item);
      };
    };
    ko.applyBindings(new ViewModel());
    .grid-stack {
      background: lightgoldenrodyellow;
    }
    .grid-stack-item-content {
      color: #2c3e50;
      text-align: center;
      background-color: #18bc9c;
    }
    <link rel="stylesheet" href="https://raw.githubusercontent.com/troolee/gridstack.js/master/dist/gridstack.css" />
    <script src="//ajax.googleapis.com/ajax/libs/jquery/1.11.1/jquery.min.js" type="text/javascript"></script>
    <script src="//cdnjs.cloudflare.com/ajax/libs/jqueryui/1.11.0/jquery-ui.js" type="text/javascript"></script>
    <script src="//maxcdn.bootstrapcdn.com/bootstrap/3.2.0/js/bootstrap.min.js" type="text/javascript"></script>
    <script src="//cdnjs.cloudflare.com/ajax/libs/lodash.js/3.5.0/lodash.min.js" type="text/javascript"></script>
    <script src="//cdnjs.cloudflare.com/ajax/libs/knockout/3.2.0/knockout-debug.js" type="text/javascript"></script>
    <script type="text/javascript" src="https://rawgit.com/troolee/gridstack.js/master/dist/gridstack.js"></script>
    
    <div class="grid-stack" data-bind="gridstack: widgets">
      <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: $parent.deleteWidget">Delete me</button>
        </div>
      </div></div><!-- <---- NO SPACE BETWEEN THESE CLOSING TAGS -->

    【讨论】:

    • 您可能指的是这部分:ko.utils.domNodeDisposal.addDisposeCallback(item, function () { self.grid.removeWidget(item); }); 虽然它出现在我的示例中,但没有调用self.grid.removeWidget(item);。现在我宁愿专注于解决这个问题的快速方法。
    • 我指的不是零件。我说的是 Knockout 编程中的正确结构。查看更新的答案。
    【解决方案2】:

    问题实际上是由&lt;/div&gt; 结束标记之间的额外空格字符引起的。 example 对此发出警告。在我的情况下,它是由代码格式化程序自动插入的,所以它没有被注意到。 HTML 模板中的行应该是&lt;/div&gt;&lt;/div&gt;&lt;!-- &lt;---- NO SPACE BETWEEN THESE CLOSING TAGS --&gt;&lt;/div&gt;&lt;/div&gt; 之间没有空格

    var ViewModel = function() {
      var self = this;
      self.grid = null;
      self.widgets = ko.observableArray([{
        x: 0,
        y: 0,
        width: 1,
        height: 1
      }, {
        x: 0,
        y: 1,
        width: 1,
        height: 1
      }]);
      self.deleteWidget = function(item) {
        console.log("widgets before", self.widgets());
        self.widgets.remove(item);
        console.log("widgets after", self.widgets());
        return false;
      };
      self.afterAddWidget = function(items) {
        if (self.grid == null) {
          self.grid = $('.grid-stack').gridstack({
            auto: false
          }).data('gridstack');
        }
        var item = _.find(items, function(i) {
          return i.nodeType == 1
        });
        self.grid.addWidget(item);
        ko.utils.domNodeDisposal.addDisposeCallback(item, function() {
          self.grid.removeWidget(item);
        });
      };
    };
    ko.applyBindings(new ViewModel());
    .grid-stack {
      background: lightgoldenrodyellow;
    }
    .grid-stack-item-content {
      color: #2c3e50;
      text-align: center;
      background-color: #18bc9c;
    }
    <link rel="stylesheet" href="https://raw.githubusercontent.com/troolee/gridstack.js/master/dist/gridstack.css" />
    <script src="//ajax.googleapis.com/ajax/libs/jquery/1.11.1/jquery.min.js" type="text/javascript"></script>
    <script src="//cdnjs.cloudflare.com/ajax/libs/jqueryui/1.11.0/jquery-ui.js" type="text/javascript"></script>
    <script src="//maxcdn.bootstrapcdn.com/bootstrap/3.2.0/js/bootstrap.min.js" type="text/javascript"></script>
    <script src="//cdnjs.cloudflare.com/ajax/libs/lodash.js/3.5.0/lodash.min.js" type="text/javascript"></script>
    <script src="//cdnjs.cloudflare.com/ajax/libs/knockout/3.2.0/knockout-min.js" type="text/javascript"></script>
    <script type="text/javascript" src="https://rawgit.com/troolee/gridstack.js/master/dist/gridstack.js"></script>
    
    <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.deleteWidget">Delete me</button>
        </div>
      </div></div><!-- <---- NO SPACE BETWEEN THESE CLOSING TAGS -->

    【讨论】:

      猜你喜欢
      • 2016-09-23
      • 2021-10-27
      • 2019-11-15
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2021-09-30
      相关资源
      最近更新 更多