删除模板时,Knockout 不处理对话框
Knockout not disposing of dialog when removing template
此处的解决方案:http://jsfiddle.net/lookitstony/24hups0e/6/
Crimson 的评论让我找到了解决方案。
我遇到 KO 和 Jquery UI 对话框的问题。对话框不会被加载它们的模板破坏。
我之前存储了一个对话框实例,并在不使用绑定处理程序的情况下一遍又一遍地重复使用它。在阅读了一些关于包含的绑定处理程序的帖子后,我觉得这也许是处理对话框的最佳方式。我用错了吗?我应该坚持使用存储的参考还是 KO 有更好的方法来处理这个问题?如果这是一个 SPA,如果我在可能有或没有这些对话框的页面之间切换,我将如何管理它?
您可以通过在此处查看我的示例来见证此行为:http://jsfiddle.net/lookitstony/24hups0e/2/
JAVASCRIPT
(function () {
ko.bindingHandlers.dialog = {
init: function (element, valueAccessor, allBindingsAccessor) {
var options = ko.utils.unwrapObservable(valueAccessor()) || {};
setTimeout(function () {
options.close = function () {
allBindingsAccessor().dialogVisible(false);
};
$(element).dialog(options);
}, 0);
//handle disposal (not strictly necessary in this scenario)
ko.utils.domNodeDisposal.addDisposeCallback(element, function () {
$(element).dialog("destroy");
});
},
update: function (element, valueAccessor, allBindingsAccessor) {
var shouldBeOpen = ko.utils.unwrapObservable(allBindingsAccessor().dialogVisible),
$el = $(element),
dialog = $el.data("uiDialog") || $el.data("dialog");
//don't call open/close before initilization
if (dialog) {
$el.dialog(shouldBeOpen ? "open" : "close");
}
}
}
})();
$(function () {
var vm = {
open: ko.observable(false),
content: ko.observable('Nothing to see here...'),
templateOne: ko.observable(true),
templateTwo: ko.observable(false),
templateOneHasDialog: ko.observable(true),
showOne: function(){
this.templateTwo(false);
this.templateOne(true);
},
showTwo: function(){
this.templateOne(false);
this.templateTwo(true);
},
diagOpt: {
autoOpen: false,
position: "center",
modal: true,
draggable: true,
width: 'auto'
},
openDialog: function () {
if(this.templateOneHasDialog()){
this.content('Dialog opened!');
this.open(open);
} else {
this.content('No Dialog Available');
}
}
}
ko.applyBindings(vm);
});
HTML
<div id='ContentContainer'>
Experience Multiple Dialogs
<ul>
<li>Click "Open Dialog"</li>
<li>Move the dialog out of the center and notice only 1 dialog</li>
<li>Close Dialog</li>
<li>Now click "One" and "Two" buttons back and forth a few times</li>
<li>Now click "Open Dialog"</li>
<li>Move the dialog and observe the multiple dialogs</li>
</ul>
<button data-bind="click:showOne">One</button>
<button data-bind="click:showTwo">Two</button>
<!-- ko if: templateOne -->
<div data-bind="template:{name:'template-one'}"></div>
<!-- /ko -->
<!-- ko if: templateTwo -->
<div data-bind="template:{name:'template-two'}"></div>
<!-- /ko -->
</div>
<script type="text/html" id="template-one">
<h3>Template #1</h3>
<p data-bind="text:content"></p>
<div><input type= "checkbox" data-bind="checked:templateOneHasDialog" /> Has Dialog </div>
<button data-bind="click:openDialog">Open Dialog</button>
<!-- ko if: templateOneHasDialog -->
<div style="display:none" data-bind="dialog:diagOpt, dialogVisible:open">
The Amazing Dialog!
</div>
<!-- /ko -->
</script>
<script type="text/html" id="template-two">
Template #2
</script>
在模板中使用 dialog
时,每次显示模板时都会调用 init
方法,因此在您的案例中会出现多个对话框。要解决此问题,请将对话框放在 template
.
之外
<div style="display:none" data-bind="dialog:diagOpt, dialogVisible:open">
The Amazing Dialog!
</div>
将其放在模板之外,现在问题将得到解决。
已更新 fiddle:Fiddle
编辑: 我查看了您的代码,发现在您的案例中没有触发 ko.utils.domNodeDisposal.addDisposeCallback
。因此,对话框没有在 returns 中显示多个对话框的模板更改时被破坏。
But why ko.utils.domNodeDisposal.addDisposeCallback
has not called?
当模板中的元素(使用自定义绑定呈现)从 DOM 中移除时,将触发 ko.utils.domNodeDisposal.addDisposeCallback
。但在您的情况下,对话框元素附加到 body
而不是 template
,因此未触发
解决方案
jquery ui 1.10.0+
可以使用 appendTo
选项指定对话框元素附加到何处,我们可以使用它来解决此问题。
diagOpt: {
autoOpen: false,
position: "center",
modal: true,
draggable: true,
width: 'auto',
appendTo: "#DesiredDivID"
},
<script type="text/html" id="template-one">
<h3>Template #1</h3>
<p data-bind="text:content"></p>
<div><input type= "checkbox" data-bind="checked:templateOneHasDialog" /> Has Dialog </div>
<button data-bind="click:openDialog">Open Dialog</button>
<!-- ko if: templateOneHasDialog -->
<div id="DesiredDivID"></div>
<div id="dlg" data-bind="dialog:diagOpt, dialogVisible:open">
The Amazing Dialog!
</div>
<!-- /ko -->
</script>
现在对话框元素将附加到 #DesiredDivID
并在模板更改时销毁。
查看更新后的 fiddle:Updated one-April-1
此处的解决方案:http://jsfiddle.net/lookitstony/24hups0e/6/ Crimson 的评论让我找到了解决方案。
我遇到 KO 和 Jquery UI 对话框的问题。对话框不会被加载它们的模板破坏。
我之前存储了一个对话框实例,并在不使用绑定处理程序的情况下一遍又一遍地重复使用它。在阅读了一些关于包含的绑定处理程序的帖子后,我觉得这也许是处理对话框的最佳方式。我用错了吗?我应该坚持使用存储的参考还是 KO 有更好的方法来处理这个问题?如果这是一个 SPA,如果我在可能有或没有这些对话框的页面之间切换,我将如何管理它?
您可以通过在此处查看我的示例来见证此行为:http://jsfiddle.net/lookitstony/24hups0e/2/
JAVASCRIPT
(function () {
ko.bindingHandlers.dialog = {
init: function (element, valueAccessor, allBindingsAccessor) {
var options = ko.utils.unwrapObservable(valueAccessor()) || {};
setTimeout(function () {
options.close = function () {
allBindingsAccessor().dialogVisible(false);
};
$(element).dialog(options);
}, 0);
//handle disposal (not strictly necessary in this scenario)
ko.utils.domNodeDisposal.addDisposeCallback(element, function () {
$(element).dialog("destroy");
});
},
update: function (element, valueAccessor, allBindingsAccessor) {
var shouldBeOpen = ko.utils.unwrapObservable(allBindingsAccessor().dialogVisible),
$el = $(element),
dialog = $el.data("uiDialog") || $el.data("dialog");
//don't call open/close before initilization
if (dialog) {
$el.dialog(shouldBeOpen ? "open" : "close");
}
}
}
})();
$(function () {
var vm = {
open: ko.observable(false),
content: ko.observable('Nothing to see here...'),
templateOne: ko.observable(true),
templateTwo: ko.observable(false),
templateOneHasDialog: ko.observable(true),
showOne: function(){
this.templateTwo(false);
this.templateOne(true);
},
showTwo: function(){
this.templateOne(false);
this.templateTwo(true);
},
diagOpt: {
autoOpen: false,
position: "center",
modal: true,
draggable: true,
width: 'auto'
},
openDialog: function () {
if(this.templateOneHasDialog()){
this.content('Dialog opened!');
this.open(open);
} else {
this.content('No Dialog Available');
}
}
}
ko.applyBindings(vm);
});
HTML
<div id='ContentContainer'>
Experience Multiple Dialogs
<ul>
<li>Click "Open Dialog"</li>
<li>Move the dialog out of the center and notice only 1 dialog</li>
<li>Close Dialog</li>
<li>Now click "One" and "Two" buttons back and forth a few times</li>
<li>Now click "Open Dialog"</li>
<li>Move the dialog and observe the multiple dialogs</li>
</ul>
<button data-bind="click:showOne">One</button>
<button data-bind="click:showTwo">Two</button>
<!-- ko if: templateOne -->
<div data-bind="template:{name:'template-one'}"></div>
<!-- /ko -->
<!-- ko if: templateTwo -->
<div data-bind="template:{name:'template-two'}"></div>
<!-- /ko -->
</div>
<script type="text/html" id="template-one">
<h3>Template #1</h3>
<p data-bind="text:content"></p>
<div><input type= "checkbox" data-bind="checked:templateOneHasDialog" /> Has Dialog </div>
<button data-bind="click:openDialog">Open Dialog</button>
<!-- ko if: templateOneHasDialog -->
<div style="display:none" data-bind="dialog:diagOpt, dialogVisible:open">
The Amazing Dialog!
</div>
<!-- /ko -->
</script>
<script type="text/html" id="template-two">
Template #2
</script>
在模板中使用 dialog
时,每次显示模板时都会调用 init
方法,因此在您的案例中会出现多个对话框。要解决此问题,请将对话框放在 template
.
<div style="display:none" data-bind="dialog:diagOpt, dialogVisible:open">
The Amazing Dialog!
</div>
将其放在模板之外,现在问题将得到解决。
已更新 fiddle:Fiddle
编辑: 我查看了您的代码,发现在您的案例中没有触发 ko.utils.domNodeDisposal.addDisposeCallback
。因此,对话框没有在 returns 中显示多个对话框的模板更改时被破坏。
But why
ko.utils.domNodeDisposal.addDisposeCallback
has not called?
当模板中的元素(使用自定义绑定呈现)从 DOM 中移除时,将触发 ko.utils.domNodeDisposal.addDisposeCallback
。但在您的情况下,对话框元素附加到 body
而不是 template
,因此未触发
解决方案
jquery ui 1.10.0+
可以使用 appendTo
选项指定对话框元素附加到何处,我们可以使用它来解决此问题。
diagOpt: {
autoOpen: false,
position: "center",
modal: true,
draggable: true,
width: 'auto',
appendTo: "#DesiredDivID"
},
<script type="text/html" id="template-one">
<h3>Template #1</h3>
<p data-bind="text:content"></p>
<div><input type= "checkbox" data-bind="checked:templateOneHasDialog" /> Has Dialog </div>
<button data-bind="click:openDialog">Open Dialog</button>
<!-- ko if: templateOneHasDialog -->
<div id="DesiredDivID"></div>
<div id="dlg" data-bind="dialog:diagOpt, dialogVisible:open">
The Amazing Dialog!
</div>
<!-- /ko -->
</script>
现在对话框元素将附加到 #DesiredDivID
并在模板更改时销毁。
查看更新后的 fiddle:Updated one-April-1