JSViews 可观察数组在删除/添加和排序时不刷新视图

JSViews observable arrays are not refreshing the view on removed / adding and sorting

我正在尝试将项目从一个数组移动到另一个数组,并按名称对它们进行排序。

这部分工作正常,似乎 observable.refresh 更新了数据本身,但视图仍然显示旧数据,使用 moveFromTo() 将移动项目,但不会更新它们在视图中的顺序。

moveFromToType2() 将显示添加的项目,但不会更新从中删除的项目。

在这两种情况下,执行 view.refresh() 都可以解决问题,但我认为这不是预期的行为。

https://jsfiddle.net/y946xhvq/

<body>
<div id="multiselect"></div>

<script id="multiselectTemplate" type="text/x-jsrender">
    <select id="leftSelect" multiple>
        {^{for left}}
            <option data-link="value{:#index}">{^{:name}}</option>
        {{/for}}
    </select>
    <button id="rightButton"> > </button>
    <button id="leftButton"> < </button>
    <select id="rightSelect" multiple>
            {^{for right}}
                <option data-link="value{:#index}">{^{:name}}</option>
            {{/for}}
    </select>
</script>

<script>
    var data = {
        left: [{ "id": 0, "name": "Melendez Garner" }, { "id": 1, "name": "Mara Orr" }, { "id": 2, "name": "Bass Salazar" }, { "id": 3, "name": "Carol Freeman" }, { "id": 4, "name": "Selma Bradford" }, { "id": 5, "name": "Cotton Parrish" }, { "id": 6, "name": "Haley Campbell" }, { "id": 7, "name": "Ruth Wright" }, { "id": 8, "name": "Carmella Blake" }],
        right: []
    }
    data.left.sort((a, b) => a.name.localeCompare(b.name));
    var m = $.templates('#multiselectTemplate').link('#multiselect', data);

    $('#multiselect').on('click', '#leftButton', function () {
        //MOVE FROM RIGHT TO LEFT
        var view = $.view(this);
        var value = $('#rightSelect').val();
        if (value === null) return;
        //moveFromToType2(data.right, data.left, value);
        moveFromTo(data.right, data.left, value);
        //view.refresh();
    }).on('click', '#rightButton', function () {
        //MOVE FROM LEFT TO RIGHT
        var view = $.view(this);
        var value = $('#leftSelect').val();
        if (value === null) return;
        //moveFromToType2(data.left, data.right, value);
        moveFromTo(data.left, data.right, value);
        //view.refresh();
    })

    function moveFromToType2(from, to, index) {
        if (from.length == 0) return;
        if (index !== undefined) {
            let selected = index.map(d => from[d]);
            selected.forEach(d => {
                let i = from.indexOf(d);
                from.splice(i, 1);
            });
            $.observable(to).insert(selected);
            to.sort((a, b) => a.name.localeCompare(b.name));
            from.sort((a, b) => a.name.localeCompare(b.name));
        }
    }

    function moveFromTo(from, to, index) {
        if (from.length == 0) return;
        if (index !== undefined) {
            let selected = index.map(d => from[d]);
            selected.forEach(d => {
                let i = from.indexOf(d);
                $.observable(from).remove(i);
            });
            $.observable(to).insert(selected);
            to.sort((a, b) => a.name.localeCompare(b.name));
            from.sort((a, b) => a.name.localeCompare(b.name));
            $.observable(to).refresh(to);
            $.observable(from).refresh(from);
        }
    }
</script>

这里的问题是您正在对 tofrom 进行不可观察的更改和可观察的更改。如果您希望 UI 在数据链接的驱动下正确更新,您只需对这些数组进行可观察到的更改。

这是一个纠正这个问题的版本,首先克隆每个数组,然后对克隆进行不可观察的更改,然后最后将克隆传递给 refresh(),以进行可观察的更新(合并所有变化):

https://jsfiddle.net/BorisMoore/qsvhm4x6/4/

function moveFromTo(from, to, index) {
    if (from.length == 0) return;
    let newFrom = from.slice(0); // Make a clone of from array
    if (index !== undefined) {
        let selected = index.map(d => newFrom[d]);
        selected.forEach(d => {
            let i = newFrom.indexOf(d);
            newFrom.splice(i, 1); // Remove selected objects from clone
        });
        let newTo = to.concat(selected); // Make a clone of to array, plus selected objects
        newTo.sort((a, b) => a.name.localeCompare(b.name)); // Sort
        newFrom.sort((a, b) => a.name.localeCompare(b.name)); // Sort
        $.observable(to).refresh(newTo); // Now observably update 'to', to the new array
        $.observable(from).refresh(newFrom); // Now observably update 'from', the new array
    }
}

这是一种不同的方法,在 {^{for}} 上使用内置的 sort feature,而不是对基础数据进行排序。它还在 <select> 元素上使用数据链接:

https://jsfiddle.net/BorisMoore/f70pnkwa/11/

<select id="leftSelect" multiple size="10" data-link="leftSelect">
    {^{for left sort="name"}}
        <option data-link="value{:id} {:name}"></option>
    {{/for}}
</select>