[英]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.