我有两个<select>
菜单和一个文本框。当选择第一个菜单中的选项时,它应该更新文本框中的值,并且还应该在第二个选择菜单中设置所选选项。
文本框正确更新。
但是,第二个选择菜单未更新。
第一个菜单中的ParentID
值应用于指定第二个菜单的TaskID
值。 ParentID
值是同一表中TaskID
的FK引用。
例如,在下面,如果在第一个菜单中选择了&#34; ManualItems&#34; ,那么&#34; Positions&#34; 应该成为第二个菜单中选择的值。
var viewModel = function(data) {
var self = this;
// variables
self.currentTask = ko.observable();
self.selectedParentTask = ko.observable();
self.taskDescription = ko.observable("");
self.tasks = ko.observableArray([
{TaskID: 1, TaskName: "ManualItems", TaskDescription: "Manual Rec", ParentID: 4, ParentName: "Positions"},
{TaskID: 2, TaskName: "Trades", TaskDescription: "Trades Data", ParentID: null, ParentName: null},
{TaskID: 3, TaskName: "File-In", TaskDescription: "File Detail", ParentID: 2, ParentName: "Trades"},
{TaskID: 4, TaskName: "Positions", TaskDescription: "Positions Overview", ParentID: null, ParentName: null}
]);
self.parentTasks = ko.observableArray([
{TaskID: 1, TaskName: "ManualItems", TaskDescription: "Manual Rec", ParentID: 4, ParentName: "Positions"},
{TaskID: 2, TaskName: "Trades", TaskDescription: "Trades Data", ParentID: null, ParentName: null},
{TaskID: 3, TaskName: "File-In", TaskDescription: "File Detail", ParentID: 2, ParentName: "Trades"},
{TaskID: 4, TaskName: "Positions", TaskDescription: "Positions Overview", ParentID: null, ParentName: null}
]);
/*
self.currentTask.subscribe(function(newValue){
self.selectedParentTask(newValue);
});
*/
self.EditTask = function () {
// populate all fields with selected task
self.taskDescription(self.currentTask().TaskDescription);
self.selectedParentTask(self.currentTask()); // set parent task to the ParentID value of currentTask
};
};
ko.applyBindings(new viewModel());
&#13;
<link href="https://maxcdn.bootstrapcdn.com/bootstrap/4.0.0-alpha.6/css/bootstrap.min.css" rel="stylesheet"/>
<script src="https://cdnjs.cloudflare.com/ajax/libs/tether/1.4.0/js/tether.min.js"></script>
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<script src="https://maxcdn.bootstrapcdn.com/bootstrap/4.0.0-alpha.6/js/bootstrap.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/knockout/3.4.2/knockout-min.js"></script>
<div class="form-group">
<label for="taskName">Edit Existing Task</label>
<select class="form-control" id="taskNameSelect" data-bind="
options: tasks,
optionsText: 'TaskName',
value: currentTask,
event: {change: $root.EditTask},
optionsCaption: 'Select Task...'
"></select>
</div>
<div class="form-group">
<label for="taskParent">Select Parent Task</label>
<select class="form-control" id="taskParent" data-bind="
options: parentTasks,
optionsText: 'TaskName',
value: selectedParentTask,
optionsCaption: 'Select Parent Task...'
"></select>
</div>
<div class="form-group">
<label for="taskDescription">Task Description</label>
<textarea class="form-control" id="taskDescription" rows="3" placeholder="Enter Task Description" data-bind="value: taskDescription"></textarea>
</div>
&#13;
以下是JSFiddle中的代码。
答案 0 :(得分:0)
通常可以使用指定ko.computed
和read
方法的write
属性来实现这种关系。
计算的read
属性指向存储“当前选择”的viewmodel的可观察私有属性。
write
方法定义新值如何设置基础可观察对象,以及副作用在任何其他属性上。
将此应用于您的第一个下拉列表,该下拉列表写入self.currentTask
:
read
引用存储选择的“private”observable:
read: current,
write
最终存储新选择:
write: function(task) {
/* ... */
current(task)
}
但在写作之前,它会检查是否有匹配的父任务:
if (task && task.ParentID) {
// Find parent task with right ID
var curParent = self.parentTasks()
.find(function(parent) {
return parent.TaskID === task.ParentID;
});
// If it's there, write to parent selection
if (curParent) {
parent(curParent);
}
}
在实施这些计算时,您还会注意到您尚未完全定义所需的关系/用户互动。
剩下的问题:
null
父母怎么办?在一个工作示例中,没有未定义的行为:
var viewModel = function(data) {
var self = this;
var current = ko.observable(null);
var parent = ko.observable(null);
self.tasks = ko.observableArray(tasks());
self.parentTasks = ko.observableArray(parentTasks());
self.currentTask = ko.computed({
read: current,
write: function(task) {
if (task && task.ParentID) {
// Find parent task with right ID
var curParent = self.parentTasks()
.find(function(parent) {
return parent.TaskID === task.ParentID;
});
// If it's there, write to parent selection
if (curParent) {
parent(curParent);
}
}
current(task);
}
});
self.parentTask = ko.computed({
read: parent,
write: function(task) {
/* To be filled in by the question asker */
parent(task);
}
});
// This can be automated via a `computed`:
self.taskDescription = ko.pureComputed(function() {
var current = self.currentTask();
var parent = self.parentTask();
return (current ? current.TaskDescription : "no existing task") +
" - (" +
(parent ? parent.TaskDescription : "no parent task") +
")";
});
};
ko.applyBindings(new viewModel());
function tasks() {
return [
{TaskID: 1, TaskName: "ManualItems", TaskDescription: "Manual Rec", ParentID: 4, ParentName: "Positions"},
{TaskID: 2, TaskName: "Trades", TaskDescription: "Trades Data", ParentID: null, ParentName: null},
{TaskID: 3, TaskName: "File-In", TaskDescription: "File Detail", ParentID: 2, ParentName: "Trades"},
{TaskID: 4, TaskName: "Positions", TaskDescription: "Positions Overview", ParentID: null, ParentName: null}
];
};
function parentTasks() {
return [
{TaskID: 1, TaskName: "ManualItems", TaskDescription: "Manual Rec", ParentID: 4, ParentName: "Positions"},
{TaskID: 2, TaskName: "Trades", TaskDescription: "Trades Data", ParentID: null, ParentName: null},
{TaskID: 3, TaskName: "File-In", TaskDescription: "File Detail", ParentID: 2, ParentName: "Trades"},
{TaskID: 4, TaskName: "Positions", TaskDescription: "Positions Overview", ParentID: null, ParentName: null}
];
};
<script src="https://cdnjs.cloudflare.com/ajax/libs/knockout/3.4.2/knockout-min.js"></script>
<div class="form-group">
<label for="taskName">Edit Existing Task</label>
<select class="form-control" id="taskNameSelect"
data-bind="options: tasks,
optionsText: 'TaskName',
value: currentTask,
optionsCaption: 'Select Task...'"></select>
</div>
<div class="form-group">
<label for="taskParent">Select Parent Task</label>
<select class="form-control" id="taskParent"
data-bind="options: parentTasks,
optionsText: 'TaskName',
value: parentTask,
optionsCaption: 'Select Parent Task...'"></select>
</div>
<div class="form-group">
<label for="taskDescription">Task Description</label>
<p class="form-control" data-bind="text: taskDescription"></p>
</div>
答案 1 :(得分:0)
作为一般规则,避免在淘汰赛中设置DOM事件处理程序。大多数情况下,通过使用订阅,您可以使用更少的代码和更少的歧义来做同样的事情。
在这种情况下,您希望通过为其找到匹配的父任务来对currentTask
中的更改做出反应。
ko.utils.arrayFirst()
是一个方便的utility function,用于从匹配特定条件的数组中提取第一个元素。 (现在您也可以使用Array#find
获得相同的效果。)
所以,我们得到:
self.currentTask.subscribe(function (task) {
var matchingParentTask = ko.utils.arrayFirst(self.parentTasks(), function (parent) {
return parent.TaskName === task.ParentName;
});
self.parentTask(matchingParentTask);
self.taskDescription(task.TaskDescription);
});
在上下文中:
var viewModel = function(data) {
var self = this;
// variables
self.currentTask = ko.observable();
self.parentTask = ko.observable();
self.taskDescription = ko.observable();
self.tasks = ko.observableArray([
{TaskID: 1, TaskName: "ManualItems", TaskDescription: "Manual Rec", ParentID: 4, ParentName: "Positions"},
{TaskID: 2, TaskName: "Trades", TaskDescription: "Trades Data", ParentID: null, ParentName: null},
{TaskID: 3, TaskName: "File-In", TaskDescription: "File Detail", ParentID: 2, ParentName: "Trades"},
{TaskID: 4, TaskName: "Positions", TaskDescription: "Positions Overview", ParentID: null, ParentName: null}
]);
self.parentTasks = ko.observableArray([
{TaskID: 1, TaskName: "ManualItems", TaskDescription: "Manual Rec", ParentID: 4, ParentName: "Positions"},
{TaskID: 2, TaskName: "Trades", TaskDescription: "Trades Data", ParentID: null, ParentName: null},
{TaskID: 3, TaskName: "File-In", TaskDescription: "File Detail", ParentID: 2, ParentName: "Trades"},
{TaskID: 4, TaskName: "Positions", TaskDescription: "Positions Overview", ParentID: null, ParentName: null}
]);
self.currentTask.subscribe(function (task) {
var matchingParentTask = ko.utils.arrayFirst(self.parentTasks(), function (parent) {
return parent.TaskName === task.ParentName;
});
self.parentTask(matchingParentTask);
self.taskDescription(task.TaskDescription);
});
};
ko.applyBindings(new viewModel());
<link href="https://maxcdn.bootstrapcdn.com/bootstrap/4.0.0-alpha.6/css/bootstrap.min.css" rel="stylesheet"/>
<script src="https://cdnjs.cloudflare.com/ajax/libs/tether/1.4.0/js/tether.min.js"></script>
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<script src="https://maxcdn.bootstrapcdn.com/bootstrap/4.0.0-alpha.6/js/bootstrap.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/knockout/3.4.2/knockout-min.js"></script>
<div class="form-group">
<label for="taskName">Edit Existing Task</label>
<select class="form-control" id="taskNameSelect" data-bind="
value: currentTask,
options: tasks,
optionsText: 'TaskName',
optionsCaption: 'Select Task...'
"></select>
</div>
<div class="form-group">
<label for="taskParent">Select Parent Task</label>
<select class="form-control" id="taskParent" data-bind="
value: parentTask,
options: parentTasks,
optionsText: 'TaskName',
optionsCaption: 'Select Parent Task...'
"></select>
</div>
<div class="form-group">
<label for="taskDescription">Task Description</label>
<textarea class="form-control" id="taskDescription" rows="3" placeholder="Enter Task Description" data-bind="value: taskDescription"></textarea>
</div>