Gridstack在删除时不更新
Posted
技术标签:
【中文标题】Gridstack在删除时不更新【英文标题】:Gridstack not updating on delete 【发布时间】: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>
【问题讨论】:
【参考方案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】:
问题实际上是由</div>
结束标记之间的额外空格字符引起的。 example 对此发出警告。在我的情况下,它是由代码格式化程序自动插入的,所以它没有被注意到。 html 模板中的行应该是</div></div><!-- <---- NO SPACE BETWEEN THESE CLOSING TAGS -->
,</div></div>
之间没有空格
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 -->
【讨论】:
以上是关于Gridstack在删除时不更新的主要内容,如果未能解决你的问题,请参考以下文章