繁体   English   中英

使用ViewModel外部的计算数组进行JS淘汰

[英]Knockout JS using computed arrays outside of ViewModel

我想在页面上显示项目列表,并能够通过使用所有位置的下拉列表来动态地重新定位项目。 从下拉列表中选择一个位置将更改该项目的当前位置,并重新移动列表中所有受影响元素的位置。

我确实有这个概念的可行版本,但这并不理想。 由于某种原因,当我引用我的selectedItems计算数组时(我通过将selectedItem设置为observable来过滤我的项目),返回的项目中包含的位置是该项目的原始位置值,而不是通过设置的位置值下拉菜单/我的重新定位功能。 这有点奇怪,因为'items'observableArray确实包含了更新后的值,而calculatedArray确实返回了正确的项目,只是没有最新的值。

正常工作的JSfiddle在下面。 但是,它进行了大量的手动计算,并且没有利用如上所述的计算数组。 问题可能与从ViewModel外部设置Knockout可观察对象有关。 要查看该问题,请取消注释“文档准备好”块中的两行,在该行中,我尝试查找项目的当前位置,并注释掉for循环,在该循环中,我手动查找当前项目。

https://jsfiddle.net/tq1m873m/5/

我是KnockoutJS和JS的新手,请保持柔和:)

$(document).ready(function () {

    $("select[id^='selectName_']").change(function () {

        //Extract the item ID from the select html id attribute
        var curItemIDNum = $(this).attr('id').substring(15);

        var currentPos = 0;

        // myViewModel.selectedItem("item" + curItemIDNum);
        // currentPos = myViewModel.selectedItems()[0].position();  

        // START - really bad code, shield your eyes
        // I can't seem to get the current position via the 2 commented lines above and have to resort to converting the observable array to a regular array and pulling the value that way. Not pretty!
        var itemsJS = ko.toJS(self.items());
        for (var x = 0; x < itemsJS.length; x++) {
            if (("item" + curItemIDNum) == itemsJS[x].name) {
                currentPos = itemsJS[x].position;
                break;
            }
        }
        // END - really bad code

        reposition("item" + curItemIDNum, currentPos, $(this).val());
        refreshDropDowns();
    });

    refreshDropDowns();

});

您之前就已经在为此工作,而我没有适合您的解决方案。 今天,我愿意。 您对jQuery触发器的使用效果不佳。 让我们用淘汰赛来完成所有工作。

我将items设置为只是一组没有分配位置的对象。 orderedItems是一种计算方法, orderedItems顺序遍历items并创建一个position的可观察值。

可观察到的该position上的预订调用moveItemTo ,该预订重新排列项目,并且所有依赖项都由Knockout更新。

 $(function() { ko.applyBindings(viewModel()); }); function item(name) { return { name: name }; } var viewModel = function() { var self = {}; self.items = ko.observableArray([ item('item1'), item('item2'), item('item4'), item('item5'), item('item3') ]); function moveItemTo(item, pos) { var oldPos = self.items.indexOf(item), newPos = pos - 1, items; if (oldPos < newPos) { items = self.items.slice(oldPos, newPos + 1); items.push(items.shift()); self.items.splice.bind(self.items, oldPos, items.length).apply(self.items, items); } else { items = self.items.slice(newPos, oldPos + 1); items.unshift(items.pop()); self.items.splice.bind(self.items, newPos, items.length).apply(self.items, items); } } self.orderedItems = ko.computed(function() { return ko.utils.arrayMap(self.items(), function(item, index) { var pos = ko.observable(index + 1); pos.subscribe(moveItemTo.bind(null, item)); return { name: item.name, position: pos }; }); }); return self; }; //end of viewmodel 
 <script src="https://ajax.googleapis.com/ajax/libs/jquery/1.9.1/jquery.min.js"></script> <script src="https://cdnjs.cloudflare.com/ajax/libs/knockout/3.2.0/knockout-min.js"></script> <div>Set the order of the item by selecting a new position from the dropdown: <ul data-bind="foreach: orderedItems"> <li> <div> <span data-bind="text: name"></span> <select data-bind="options: $root.orderedItems, optionsValue:'position', value: position"></select> </div> </li> </ul> </div>ITEMS CONTENTS: <BR> <span data-bind="text: JSON.stringify(ko.toJS(items), null, 4)"></span> 

我可以想到的一种方法是使用计算出的值来保存头寸的当前状态。 当在如下所示的项目上设置新职位时,这将允许您进行改组:

ko.utils.arrayForEach(self.items(), function (x) {
        x.newPosition = ko.computed({
            read: function () {
                return x.position();
            },
            write: function (val) {
                //get the item in the prev position
                var temp = ko.utils.arrayFirst(self.items(), function (y) {
                    return y.position() == val;
                });
                //swap positons here
                if (temp) {
                    temp.position(x.position());
                    x.position(val);
                }
            }
        });
    });

在标记中

<select data-bind="options:positions,value:newPosition"></select>

如此计算得出的“写入”值...脚本会交换位置值。 我将您的原始绑定留给了orderedItems。 您可以在这里https://jsfiddle.net/p1yhmvcr/2/找到一个工作示例。这里值得注意的一件事是排序并不是真正的物理。 可观察的数组项仍在数组的原始索引上,并且代码仅更改位置值。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM