我有一个 3 层级联选择列表,我使用 knockout.js/jQuery/json 实现了它。
在某些情况下,选择框内只有 1 个选择 - 在这种情况下,我不想强迫用户必须手动选择它,而是将其默认为单个值,然后向下级联到自动下一个框。这可以吗?
我的选择列表(第一个列表目前略有不同,因为它是由 MVC Razor View 生成的,并且值直接从 View 模型提供):
<!--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>
我的 knockout 码:
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)强制调用填充下一个级别的代码?不知道如何在不破坏这一切的情况下做到这一点!
最佳答案
哎呀!不要像这样混合 jQuery 和 Knockout。不要让 jQuery 进行 DOM 操作(例如 val(...)
),而是从 View 模型中获取选定的值。
这也将极大地简化您的 View ,例如id
之类的东西属性变得无关紧要。
此外,我建议制作 Fetch...
方法是 View 模型的依赖项。在下面的示例中,我只是将这些函数内联到 View 模型构造函数中,但您也可以将它们包装在服务中并将该服务作为依赖项(当然,您仍然必须向该服务提供输入和成功处理程序) .
如果您遵循上述建议,另一件事非常需要/有用:使用 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>
关于javascript - 使用默认值进行级联选择,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/34768980/