javascript - 使用默认值进行级联选择

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

我有一个 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/

相关文章:

javascript - React 中的加载器

javascript - jQuery 函数在 MVC 局部 View 中不起作用

asp.net-mvc - 如何动态绑定(bind)kendo mvc ui下拉列表

javascript - 如何使用 jQuery 异步上传文件?

javascript - 更改字体 dateTimeLabel Highstock

javascript - Highcharts 基于数据系列值自定义工具提示显示

javascript - JQuery 选择器选择性选择

javascript - 在 Vanilla JS 中滚动到下一部分并返回到顶部而无需 ID - 无 JQUERY

javascript - 无法读取未定义的属性 "name"

asp.net-mvc - ASP .NET MVC - DropDownList OnChange