2016-01-13 279 views
0

我有一个3层级联选择列表,我已经使用knockout.js/jQuery/json实现。级联选择默认值

有些情况下,选择框中只有一个选择 - 在这种情况下,我不想强​​制用户不得不手动选择它,而是将其默认为单个值,然后级联到下一个框自动。这可以做到吗?

我的选择列表(第一个是目前略有不同,因为它是由MVC剃刀产生的视图与视图模型提供直接值):

<!--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)强制调用填充下一级的代码的调用?不知道如何做,但没有打破一切,但!

回答

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); 
    } 
} 

简单地说,如果只有一个这种选择第一个选项,并允许在需要时淘汰赛处理更新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>

+0

非常感谢 - 我扯下一些代码从一个jQuery版本我的工作因此混搭 - 它似乎工作,但我需要做的第一下拉相同 - 如果只有一次选择,选择它并填充下拉2 - 但是,这是由MVC视图模型预先填充 - 我应该交换工作与其他2次下降相同的方式?如果是这样,我可以强制页面加载时?这是否也会级联下来,如果1,2和3只有一个选择,他们都会被填满? – chilluk

+0

另外我创建了我的FetchVariant()函数,但是我不能为我的生活访问所得到的数据 - 我是否必须将observableArray映射到另一个模型以便能够在整个页面中使用它? – chilluk

+0

你问的是非常广泛的后续问题。我建议为每个单独的案例询问一个新的Stack Overflow问题,包括每个问题的简化示例。另外,您可能需要一位朋友或同事帮助思考设计。另外,如果你还没有,请查看KnockoutJS教程。 (通过KnockoutJS将客户端MVVM与服务器端预填充选择框混合在一起可能是一个多毛的主题...) – Jeroen