我有一个包含所有可用审批级别的选择菜单列表(self.approvalLevels observable array)。
我有一个包含3个选定审批级别的有序列表(self.userSelectedApprovalLevels可观察数组)。这些按优先级排序。
我希望self.userSelectedApprovalLevels中的项目可观察在选择菜单列表中标记为已选中。
我该怎么做?
var viewModel = function() {
var self = this;
self.approvalLevels = ko.observableArray([]); // observable array to store list of all available approval levels
self.userSelectedApprovalLevels = ko.observableArray([]); // observable array to store list of approval levels selected by the user
self.approvalLevels = ko.observableArray([{
"ApprovalLevelID": 1,
"ApprovalLevelName": "Analyst"
},
{
"ApprovalLevelID": 2,
"ApprovalLevelName": "Supervisor"
},
{
"ApprovalLevelID": 3,
"ApprovalLevelName": "Tester"
},
{
"ApprovalLevelID": 4,
"ApprovalLevelName": "Manager"
}
]);
self.userSelectedApprovalLevels = ko.observableArray([{
"ApprovalLevelID": 2,
"ApprovalLevelName": "Supervisor",
"ApprovalLevelPriority": 0
},
{
"ApprovalLevelID": 1,
"ApprovalLevelName": "Analyst",
"ApprovalLevelPriority": 1
},
{
"ApprovalLevelID": 3,
"ApprovalLevelName": "Tester",
"ApprovalLevelPriority": 2
}
]);
};
ko.applyBindings(new viewModel());

<link href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.7/css/bootstrap.min.css" rel="stylesheet" />
<script src="https://cdnjs.cloudflare.com/ajax/libs/knockout/3.4.2/knockout-min.js"></script>
<div class="row">
<div class="col-lg-6">
<div class="form-group">
<label for="approvalList">Select Approval Level(s)</label>
<select multiple="multiple" class="form-control" id="approvalLevelList" data-bind="options: approvalLevels, selectedOptions: userSelectedApprovalLevels, optionsText: 'ApprovalLevelName', optionsvalue: 'ApprovalLevelName'"></select>
<small id="approvalLevelList" class="form-text text-muted">Select Approval Levels Required for this Task.</small>
</div>
</div>
<div class="col-lg-6">
<p>Sort in Order of Approval level (Highest to Lowest):</p>
<ol id="selectedApprovalLevelsList" data-bind="foreach: userSelectedApprovalLevels">
<li class="list-group-item-info">
<span data-bind="text: ApprovalLevelName"> </span>
</li>
</ol>
</div>
</div>
&#13;
答案 0 :(得分:0)
要正确链接选择,他们需要引用相同的对象,或者引用可以使用===
进行比较的基元。< / p>
我的建议是在self.approvalLevels
内创建一次的源对象。要设置初始选择,请将对此数组中项目的引用添加到selectedApprovalLevels
,如下所示:
self.userSelectedApprovalLevels = ko.observableArray([
self.approvalLevels()[0],
self.approvalLevels()[1],
self.approvalLevels()[2]
]);
现在,所选列表不会被排序,但会正确同步。
要对列表进行排序,我们会创建一个额外的computed
图层,用于选择并重新排列它们:
self.sortedSAL = ko.pureComputed(function() {
return self.userSelectedApprovalLevels().sort(function(a, b) {
return a.ApprovalLevelPriority - b.ApprovalLevelPriority;
});
});
我把它放在下面的工作示例中。
var viewModel = function() {
var self = this;
self.approvalLevels = ko.observableArray([]); // observable array to store list of all available approval levels
self.userSelectedApprovalLevels = ko.observableArray([]); // observable array to store list of approval levels selected by the user
self.approvalLevels = ko.observableArray([
{
"ApprovalLevelID": 1,
"ApprovalLevelName": "Analyst",
"ApprovalLevelPriority": 1
},
{
"ApprovalLevelID": 2,
"ApprovalLevelName": "Supervisor",
"ApprovalLevelPriority": 0
},
{
"ApprovalLevelID": 3,
"ApprovalLevelName": "Tester",
"ApprovalLevelPriority": 2
},
{
"ApprovalLevelID": 4,
"ApprovalLevelName": "Manager",
"ApprovalLevelPriority": 2
}
]);
self.userSelectedApprovalLevels = ko.observableArray(
// Initial selections:
self.approvalLevels().slice(0, 3)
);
self.sortedSAL = ko.pureComputed(function() {
return self.userSelectedApprovalLevels().sort(function(a, b) {
return a.ApprovalLevelPriority - b.ApprovalLevelPriority;
});
});
};
ko.applyBindings(new viewModel());
<link href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.7/css/bootstrap.min.css" rel="stylesheet" />
<script src="https://cdnjs.cloudflare.com/ajax/libs/knockout/3.4.2/knockout-min.js"></script>
<div class="row">
<div class="col-lg-6">
<div class="form-group">
<label for="approvalList">Select Approval Level(s)</label>
<select multiple="multiple" class="form-control" id="approvalLevelList" data-bind="options: approvalLevels, selectedOptions: userSelectedApprovalLevels, optionsText: 'ApprovalLevelName', optionsvalue: 'ApprovalLevelName'"></select>
<small id="approvalLevelList" class="form-text text-muted">Select Approval Levels Required for this Task.</small>
</div>
</div>
<div class="col-lg-6">
<p>Sort in Order of Approval level (Highest to Lowest):</p>
<ol id="selectedApprovalLevelsList" data-bind="foreach: sortedSAL">
<li class="list-group-item-info">
<span data-bind="text: ApprovalLevelName"> </span>
</li>
</ol>
</div>
</div>
编辑有关两个单独的普通对象列表的要求
如果您要从服务器检索两个列表,最好创建一个客户端 viewmodel ,它将您需要的数据组合在一起。您可以使用<select>
的列表作为主要来源,并根据第二个列表添加computed sortOrder
属性:
sortOrder: ko.pureComputed(function() {
var match = apSortData().find(function(item) {
return item.ApprovalLevelID === data.ApprovalLevelID;
});
return match ? match.ApprovalLevelPriority : 0;
})
在一个工作示例中,排序顺序数据在源信息后1秒内出现:
var viewModel = function() {
var self = this;
var apSortData = ko.observableArray([]);
setTimeout(function() {
// To show they are linked automatically
apSortData(getSortOrderData());
}, 1000)
var ApprovalLevelVM = function(data) {
return Object.assign(
{},
data,
{
sortOrder: ko.pureComputed(function() {
var match = apSortData().find(function(item) {
return item.ApprovalLevelID === data.ApprovalLevelID;
});
return match ? match.ApprovalLevelPriority : 0;
})
}
);
};
self.approvalLevels = ko.observableArray(
getApprovalLevelData().map(ApprovalLevelVM)
);
self.userSelectedApprovalLevels = ko.observableArray(
// Initial selections:
self.approvalLevels().slice(0, 3)
);
self.sortedSAL = ko.pureComputed(function() {
return self.userSelectedApprovalLevels()
.sort(function(a, b) {
return a.sortOrder() - b.sortOrder();
});
}).extend({"deferred": true});
};
ko.applyBindings(new viewModel());
function getApprovalLevelData() {
return [{
"ApprovalLevelID": 1,
"ApprovalLevelName": "Analyst"
},
{
"ApprovalLevelID": 2,
"ApprovalLevelName": "Supervisor"
},
{
"ApprovalLevelID": 3,
"ApprovalLevelName": "Tester"
},
{
"ApprovalLevelID": 4,
"ApprovalLevelName": "Manager"
}
];
};
function getSortOrderData() {
return [{
"ApprovalLevelID": 2,
"ApprovalLevelName": "Supervisor",
"ApprovalLevelPriority": 0
},
{
"ApprovalLevelID": 1,
"ApprovalLevelName": "Analyst",
"ApprovalLevelPriority": 1
},
{
"ApprovalLevelID": 3,
"ApprovalLevelName": "Tester",
"ApprovalLevelPriority": 2
}
];
}
<link href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.7/css/bootstrap.min.css" rel="stylesheet" />
<script src="https://cdnjs.cloudflare.com/ajax/libs/knockout/3.4.2/knockout-min.js"></script>
<div class="row">
<div class="col-lg-6">
<div class="form-group">
<label for="approvalList">Select Approval Level(s)</label>
<select multiple="multiple" class="form-control" id="approvalLevelList" data-bind="options: approvalLevels, selectedOptions: userSelectedApprovalLevels, optionsText: 'ApprovalLevelName', optionsvalue: 'ApprovalLevelName'"></select>
<small id="approvalLevelList" class="form-text text-muted">Select Approval Levels Required for this Task.</small>
</div>
</div>
<div class="col-lg-6">
<p>Sort in Order of Approval level (Highest to Lowest):</p>
<ol id="selectedApprovalLevelsList" data-bind="foreach: sortedSAL">
<li class="list-group-item-info">
<span data-bind="text: ApprovalLevelName + ' - '+ sortOrder()"> </span>
</li>
</ol>
</div>
</div>
答案 1 :(得分:0)
所以我认为这个问题的关键是多选择不喜欢为selectedOptions bindng创建一个对象数组。我试图通过使用可写的observable来解决这个限制。写作部分可能比我使用的if语句做得更好,但你可以理解。
这是工作小提琴。https://jsfiddle.net/j3zk5uw9/3/
这是可写的可观察的。
this.userSelectedApprovalLevelWritable = ko.pureComputed({
read: function() {
var ApprovalLevelIDs = ko.utils.arrayMap(self.userSelectedApprovalLevels(), function(item) {
return item.ApprovalLevelID;
});
return ApprovalLevelIDs.sort();
},
write: function(value) {
self.userSelectedApprovalLevels.removeAll();
for (var i = 0; i < value.length; i++) {
if (value[i] === 2) {
self.userSelectedApprovalLevels.push({
"ApprovalLevelID": 2, "ApprovalLevelName": "Supervisor",
"ApprovalLevelPriority": 0
})
}
if (value[i] === 1) {
self.userSelectedApprovalLevels.push({
"ApprovalLevelID": 1, "ApprovalLevelName": "Analyst",
"ApprovalLevelPriority": 1
})
}
if (value[i] === 3) {
self.userSelectedApprovalLevels.push({
"ApprovalLevelID": 3, "ApprovalLevelName": "Tester",
"ApprovalLevelPriority": 2
})
}
if (value[i] === 4) {
self.userSelectedApprovalLevels.push({
"ApprovalLevelID": 4, "ApprovalLevelName": "Manager",
"ApprovalLevelPriority": 3
})
}
}
},
owner: this
});
答案 2 :(得分:0)
正如@ user3297291所说,选择时拥有相同的对象是件好事。如果没有ApprovalLevelPriority
,您可以在推入阵列之前将其添加到对象,但是您需要有一个逻辑来分配优先级编号
这是我的方法: 您可以在选择中添加更改事件,并添加一个observable,每次选择项目时都会保存selectedOptions。
示例:https://jsfiddle.net/21dcxh2c/4/
<强> HTML:强>
<div class="row">
<div class="col-lg-6">
<div class="form-group">
<label for="approvalList">Select Approval Level(s)</label>
<select multiple="multiple" class="form-control" id="approvalLevelList" data-bind="options: approvalLevels, selectedOptions: selectedApproval, optionsText: 'ApprovalLevelName', optionsvalue: 'ApprovalLevelName',event: {change: addApproval}"></select>
<small id="approvalLevelList" class="form-text text-muted">Select Approval Levels Required for this Task.</small>
</div>
</div>
<div class="col-lg-6">
<p>Sort in Order of Approval level (Highest to Lowest):</p>
<ol id="selectedApprovalLevelsList" data-bind="foreach: userSelectedApprovalLevels">
<li class="list-group-item-info">
<span data-bind="text: ApprovalLevelName"> </span>
</li>
</ol>
</div>
</div>
<强> JS 强>
var viewModel = function() {
var self = this;
self.approvalLevels = ko.observableArray([]); // observable array to store list of all available approval levels
self.userSelectedApprovalLevels = ko.observableArray([]); // observable array to store list of approval levels selected by the user
self.selectedApproval = ko.observable();
self.userSelectedApprovalLevels = ko.observableArray([]);
self.approvalLevels = ko.observableArray([{
"ApprovalLevelID": 1,
"ApprovalLevelName": "Analyst"
}, {
"ApprovalLevelID": 2,
"ApprovalLevelName": "Supervisor"
}, {
"ApprovalLevelID": 3,
"ApprovalLevelName": "Tester"
}, {
"ApprovalLevelID": 4,
"ApprovalLevelName": "Manager"
}]);
self.addApproval = function() {
var duplicate = false;
var obj = self.selectedApproval()[0]
ko.utils.arrayForEach(self.userSelectedApprovalLevels(), function(element) {
if (obj.ApprovalLevelID == element.ApprovalLevelID) {
return duplicate = true
}
});
if (!duplicate) {
// here you can add your priority to the object
// right now I am adding the ApprovalLevelID as ApprovalLevelPriority you probably will have your logic
obj.ApprovalLevelPriority = obj.ApprovalLevelID
self.userSelectedApprovalLevels.push(obj)
} //else you can remove if it already exists
}
self.sortSelection = ko.computed(function() {
return self.userSelectedApprovalLevels().sort(function(a, b) {
return a.ApprovalLevelPriority > b.ApprovalLevelPriority;
});
});
};
ko.applyBindings(new viewModel());