问题
I'm trying to get a multiple-nested accordion control to work with Knockout but when adding panels the items created through KO bindings do not bind with the accordion as new panels.
The code looks like this:
<div data-bind="accordion: {collapsible: true, active: false, heightStyle: 'content'}, template: { name: 'queryTemplate', foreach: children }">
</div>
<script id="queryTemplate" type="text/html">
<h3>
<div>
<a href="#" data-bind="text: id"></a>
<span data-bind="text: name"></span>
<button data-bind="click: addNext">Add Next Item</button>
</div>
</h3>
<div >
<input data-bind="value: name"></input>
<input data-bind="value: id"></input>
<button data-bind="click: addSubitem">Add SubItem</button>
<hr/>
<div data-bind="accordion: {collapsible: true, active: false, heightStyle: 'content'}, template: { name: 'queryTemplate', foreach: children }">
</div>
</div>
</script>
<script>
ko.bindingHandlers.accordion = {
init: function(element, valueAccessor) {
var options = valueAccessor() || {};
setTimeout(function() {
$(element).accordion(options);
}, 0);
//handle disposal (if KO removes by the template binding)
ko.utils.domNodeDisposal.addDisposeCallback(element, function(){
$(element).accordion("destroy");
});
},
update: function(element, valueAccessor) {
var options = valueAccessor() || {},
existing = $(element).data("accordion");
//if it has been reinitialized and our model data changed, then need to recreate until they have a "refresh" method
if (existing) {
$(element).accordion("destroy").accordion(options);
//$(element).accordion("refresh");
}
}
};
function Item(id, name, parent) {
var self = this;
this.id = ko.observable(id);
this.name = ko.observable(name);
this.children = ko.observableArray();
this.addSubitem = function(){
self.children.push(new Item(self.children().length + 1, "", this));
}
this.parent = ko.observable(parent);
this.addNext = function(){parent.addSubitem()};
}
var model = new Item(0, "Top");
var tmp = new Item(1, "First", model);
tmp.children.push(new Item(0, "SubItem!", tmp));
model.children.push(tmp);
tmp = new Item(2, "Second", model);
tmp.children.push(new Item(0, "SubItem!", tmp));
model.children.push(tmp);
ko.applyBindings(model);
</script>
I have the impression it may be due to how I'm building the template loop, but I'm at my wits end with this - thank you, anyone
NOTE:
I'll try to clarify the problem I'm having - (here's on fiddle: http://jsfiddle.net/QChon/aUJFg/4/)
The accordion and nested accordions load correctly, following the view model (Item with a "children" array containing again Item objects, which should go on indefinitely).
The "Add Next Item" button adds a sibling to the current Item, and hence to the current accordion panel, and the "Add SubItem" adds a child to the current Item's children, and hence a nested accordeon panel under the current panel.
THe problem is that when I click the buttons, the correct html elements are added at the correct places (i.e., as header and as content panel) but the jquery classes and ids are not bound to the created html controls, hence do not render nor behave correctly as part of the accordion structure. Hope that clarifies somewhat.
回答1:
The problem is in your custom bindings function
You are checking if the current element is an accordion by looking into the data-accordion attribute, which does not exist even on a properly initialized accordion. Secondly even if it finds that attribute it will try to 'recreate' the accordion on the wrong level. The container class of the accordion is the parent's parent, relative to the element that you get in the update method.
So if you change your function from this
var existing = $(element).data("accordion");
if (existing) $(element).accordion("destroy").accordion(options);
to this
var existing = $(element).parent().parent().hasClass("ui-accordion");
if (existing) $(element).parent().parent().accordion('refresh');
it should work as expected.
http://jsfiddle.net/M9222/1/
来源:https://stackoverflow.com/questions/19210897/multiple-nested-jquery-ui-accordion-generated-through-knockout-template-does-not