我有一个3层级联选择列表,我使用knockout.js / jQuery / json实现。
有些情况下,选择框中只有一个选项 - 在这种情况下,我不想强迫用户必须手动选择它,而是将其默认为单个值,然后级联到下一个框自动。可以这样做吗?
我的选择列表(第一个目前略有不同,因为它是由MVC Razor视图生成的,其值直接来自视图模型):
<!--Variants-->
<select class="dim" data-bind="value: selectedDim1" id="Dim1" name="Dim1" onchange="FetchDim2();"><option selected="selected" value="">Select Colour</option>
<option value="Black">Colour:Black</option>
<option value="NAVYBLUE">Colour:Navy Blue</option>
</select>
<select id="Dim2" data-bind="value: selectedDim2, options: ddlDim2, optionsText: 'Text', optionsValue: 'Value', optionsCaption: 'Select Waist Size'" class="dim"></select>
<select id="Dim3" data-bind="value: selectedDim3, options: ddlDim3, optionsText: 'Text', optionsValue: 'Value', optionsCaption: 'Select Leg Length'" class="dim"></select>
我的淘汰代码:
function DDLViewModel() {
this.ddlDim1 = ko.observableArray([]);
this.ddlDim2 = ko.observableArray([]);
this.ddlDim3 = ko.observableArray([]);
this.selectedDim1 = ko.observable();
this.selectedDim1.subscribe(FetchDim2, this);
this.selectedDim2 = ko.observable();
this.selectedDim2.subscribe(FetchDim3, this);
this.selectedDim3 = ko.observable();
this.selectedDim3.subscribe(FetchVariant, this);
}
var objVM = new DDLViewModel();
// Activates knockout.js
ko.applyBindings(objVM);
function FetchDim2() {
$.ajax({
type: 'POST',
url: '/product/getdims/', // we are calling json method
dataType: 'json',
// here we get value of selected dim.
data: { id: 20408,
level: 2,
head: 'Waist Size',
code: $("#Dim1").val()
},
success: function (dims) {
// dims contains the JSON formatted list of dims passed from the controller
objVM.ddlDim2(dims);
objVM.ddlDim3.removeAll();
},
error: function (ex) {
alert('Failed to retrieve dims.' + ex);
}
});
}
function FetchDim3() {
$.ajax({
type: 'POST',
url: '/product/getdims/', // we are calling json method
dataType: 'json',
// here we get value of selected dim.
data: { id: 20408,
level: 3,
head: 'Leg Length',
code: $("#Dim2").val()
},
success: function (dims) {
// dims contains the JSON formatted list of dims passed from the controller
objVM.ddlDim3(dims);
},
error: function (ex) {
alert('Failed to retrieve dims.' + ex);
}
});
}
我想我(a)需要指定一个默认值,如果只有选择和(b)强制调用填充下一级别的代码?不知道怎么做而不打破它们!
答案 0 :(得分:1)
糟糕!不要混淆jQuery和Knockout。不要让jQuery执行DOM操作(例如val(...)
),而是从视图模型中获取选定的值。
这也会大大简化您的观看,因为那些id
属性变得无关紧要。
此外,我建议将Fetch...
方法作为视图模型的依赖项。在下面的示例中,我只是在视图模型构造函数中内联这些函数,但您也可以将它们包装在服务中并将该服务作为依赖项(当然,您仍然必须为该服务提供输入和成功处理程序)
另一件事,如果您遵循上述建议,则非常需要/有用:使用var self = this
成语,而不是在任何地方重复this
/在任何地方提供this
参数。
随着所有这些事情发生变化,修复原始问题变得微不足道。触发级联更新可以在成功函数内完成。在我展示完整的代码片段之前,这是您实际问题的细节:
success: function(dims) {
self.ddlDim3(dims);
if (dims.length === 1) {
self.selectedDim3(dims[0].Value);
}
}
简单地说,如果只有一个选项,则选择第一个选项,并让Knockout处理更新DOM(如果需要,还可以级联)。
以下是基于原始代码的完整演示:
// Fake the Ajax requests:
var $ = {
ajax: function(options) {
if (options.data.level === 2 && options.data.code === "Black") {
options.success([{
Text: "Waist size S",
Value: "S"
}, {
Text: "Waist size M",
Value: "M"
}, {
Text: "Waist size L",
Value: "L"
}]);
}
if (options.data.level === 2 && options.data.code === "NAVYBLUE") {
options.success([{
Text: "Waist size M",
Value: "M"
}]);
}
// Not faking lvl 3 as extensively, but the same would hold as above.
if (options.data.level === 3) {
options.success([{
Text: "Legs 40",
Value: "40"
}]);
}
}
};
function DDLViewModel() {
var self = this;
self.ddlDim1 = ko.observableArray([]);
self.ddlDim2 = ko.observableArray([]);
self.ddlDim3 = ko.observableArray([]);
self.selectedDim1 = ko.observable();
self.selectedDim1.subscribe(FetchDim2);
self.selectedDim2 = ko.observable();
self.selectedDim2.subscribe(FetchDim3);
self.selectedDim3 = ko.observable();
self.selectedDim3.subscribe(FetchVariant);
function FetchDim2() {
console.log(2);
$.ajax({
url: '/product/getdims/',
data: {
id: 20408,
level: 2,
head: 'Waist Size',
code: self.selectedDim1()
},
success: function(dims) {
self.ddlDim2(dims);
self.ddlDim3.removeAll();
if (dims.length === 1) {
self.selectedDim2(dims[0].Value);
} else {
self.selectedDim2(null);
}
}
});
}
function FetchDim3() {
if (!self.selectedDim2()) {
self.ddlDim3.removeAll();
} else {
$.ajax({
data: {
id: 20408,
level: 3,
head: 'Leg Length',
code: self.selectedDim2()
},
success: function(dims) {
self.ddlDim3(dims);
if (dims.length === 1) {
self.selectedDim3(dims[0].Value);
}
}
});
}
}
function FetchVariant() {
// Noop / not provided in question
}
}
ko.applyBindings(new DDLViewModel());
<script src="https://cdnjs.cloudflare.com/ajax/libs/knockout/3.2.0/knockout-min.js"></script>
<select data-bind="value: selectedDim1">
<option selected="selected" value="">Select Colour</option>
<option value="Black">Colour:Black</option>
<option value="NAVYBLUE">Colour:Navy Blue</option>
</select>
<select data-bind="value: selectedDim2, options: ddlDim2, optionsText: 'Text', optionsValue: 'Value', optionsCaption: 'Select Waist Size'"></select>
<select data-bind="value: selectedDim3, options: ddlDim3, optionsText: 'Text', optionsValue: 'Value', optionsCaption: 'Select Leg Length'"></select>