级联选择默认值

时间:2016-01-13 14:15:54

标签: javascript jquery asp.net-mvc razor knockout.js

我有一个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)强制调用填充下一级别的代码?不知道怎么做而不打破它们!

1 个答案:

答案 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>