knockout.js 从DOM而不是ViewModel更新Knockout 'attr'绑定

kyks70gy  于 2022-11-10  发布在  其他
关注(0)|答案(2)|浏览(146)

我使用Knockout.js来填充一组HTML5 <details>元素。结构如下:

<div class="items" data-bind="foreach: Playlists">
    <details class="playlist-details" data-bind="attr: {id: 'playlist-details-' + $index(), open: isOpen}">
        <summary>
            <span data-bind="text: name"></span> - <span data-bind="text: count"></span> item(s)
            <div class="pull-right">
                <button data-bind="click: $parent.play, css: {disabled: count() == 0}, attr: {title: playbtn_title}" class="btn"><i class="icon-play"></i> Play</button>
                <button data-bind="click: $parent.deleteList" class="btn btn-danger"><i class="icon-trash"></i> Delete</button>
            </div>
        </summary>
        <div class="list" data-bind="with: items" style="padding-top: 2px;">
            ...
        </div>
    </details>
</div>

ViewModel中的数据如下所示:

var VM = {
    Playlists: [
        {
            name: "My Playlist1",
            count: 3,
            items: [<LIST OF SONG ID'S>],
            playbtn_title: "Play this playlist",
            isOpen: true
        },
        {
            name: "My Playlist2",
            count: 5,
            items: [<LIST OF SONG ID'S>],
            playbtn_title: "Play this playlist",
            isOpen: null
        },
        {
            name: "My Playlist3",
            count: 0,
            items: [],
            playbtn_title: "You need to add items to this list before you can play it!",
            isOpen: null
        }
    ]
};

我已经添加了使用ViewModel的isOpen属性和attr绑定来记住细节视图的open or closed state的功能(如最初描述的here)。
但是,当我单击<summary>以展开详细信息时,ViewModel没有得到更新-与value绑定不同,attr绑定不是双向的。
如何在属性值更改时更新此绑定?
我知道浏览器在打开或关闭元素时会触发一个DOMSubtreeModified事件,但是我;我不确定我会在那里放什么--我尝试过的几种方法(包括.notifySubscribers()if (list.open()) ...等)会导致循环,其中被更改的属性会再次触发事件,这会再次更改属性,这会再次触发事件,等等。

tyg4sfes

tyg4sfes1#

使用$直接播放DOM不是ko方式:-)
只需为HTML5 details标签创建一个双向绑定,它在ko中很便宜。
http://jsfiddle.net/gznf3/

ko.bindingHandlers.disclose = {
    init: function(element, valueAccessor) {
        if (element.tagName.toLowerCase() !== 'details') {
            throw "\"disclose\" binding only works on <details> tag!";
        }
        var value = valueAccessor();
        if (ko.isObservable(value)) {
            $(element).on("DOMSubtreeModified", function() {
               value($(element).prop('open'));
            });
        }
    },
    update: function(element, valueAccessor) {
        $(element).prop('open', ko.unwrap(valueAccessor()));
    }
};
vhmi4jdf

vhmi4jdf2#

最后我发现的工作方式是让DOMSubtreeModified“手动”更新值:

$(document).on('DOMSubtreeModified', 'details.playlist-details', function(e) {
    var list = ko.dataFor(this);
    list.open(this.getAttribute('open'));
});

(不知何故,这不会导致我尝试的更复杂的构造所导致的循环。)

相关问题