Multiple nested JQuery UI Accordion generated through Knockout template does not bind correctly

爷,独闯天下 提交于 2019-12-25 01:46:13

问题


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>&nbsp;
            <span data-bind="text: name"></span>&nbsp;
            <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

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!