【问题标题】:JSViews observable arrays are not refreshing the view on removed / adding and sortingJSViews 可观察数组在删除/添加和排序时不会刷新视图
【发布时间】:2020-02-06 20:26:45
【问题描述】:

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

这部分工作正常,似乎 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>

【问题讨论】:

    标签: jsrender jsviews


    【解决方案1】:

    那里的问题是您正在对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,而不是对底层数据进行排序。它还在&lt;select&gt; 元素上使用数据链接:

    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>
    

    【讨论】:

    • 我之前确实使用过排序,但是由于我使用索引而不是项目ID,这导致我的movefromto逻辑中断,因此第二个解决方案是完美的。感谢您的帮助
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2017-10-31
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多