【问题标题】:Knockout Change Event Firing when updating data set (dependant dropdowns)更新数据集时触发 Knockout Change Event(相关下拉菜单)
【发布时间】:2016-02-15 23:00:30
【问题描述】:

我希望这只是我有点修剪,但是当我不希望更改事件触发时,我遇到了麻烦。我会尽量保持简短和清晰。

我有两个下拉菜单,国家和城市。两者的约束如下:

<select data-bind="options: Countries, event: { change: IChanged }, value: CountrySelected">
<select data-bind="options: Cities, event: { change: IChanged }, value: CitySelected">

我的小视图模型

self.Countries = ko.observableArray([]);
self.Cities = ko.observableArray([]);
self.CountrySelected = ko.observable();
self.CitySelected = ko.observable();

现在我的函数IChanged()

self.IChanged = function(item) {
    GoGetMyOptions().done(function(response) {
        self.Cities(response);    
    });
}

问题!

调用self.Cities(response);时会触发City下拉菜单的change事件,这意味着下拉菜单会再次调用该方法。

警告

我已经简化了这个,我可以有 1 到 80 个过滤器。在我的代码中,我基本上开始加载右侧所有内容的下拉选项,问题是它为右侧所有内容调用更改事件:O Ideas any?

一个更复杂的例子(接近我的代码

我其实有一个过滤器集合,self.FilterCollection,每个过滤器都有以下内容:

self.DropDownValues = ko.observableArray([]);
self.SelectedValue = ko.observable();

You can see that when a drop down is selected, it updates the selected value and THEN refreshed the DropDownValues array for all filters to the right.

在一个相当尴尬的场景中,

  1. 用户选择了一个城市
  2. 他们选择了一个国家
  3. CITY 列表已更新
  4. 因此重置当前值**

我相信数字 4 会触发订阅...

一个完整的场景

有 4 个下拉菜单,A、B、C 和 D。

当用户从 A 中选择一个值时,我将遍历剩余的下拉菜单并调用 getValues,然后这将更新 DropDownValues 可观察对象。

因此,我希望 1 UI 事件触发说“用户更改了下拉 a”,然后我需要进行 3 ajax 调用来加载 B、C和 D 并更新可观察数组。

我的问题是,当用户选择 A 时,它会正确地进行 3 次 ajax 调用,但是在设置 B 的值时会触发事件...

这意味着 B 将进行 2 次 ajax 调用来更新 C 和 D。因此,当用户在下拉 A 中选择某些内容时,它实际上会触发:

1 个 UI 事件,3 个 Ajax 调用,1 个 UI 事件,2 个 ajax 调用,1 个 UI 事件,1 个 ajax 调用,然后是一个最终的 UI 事件。总而言之,用户一键进行 4 次 UI 事件调用和 6 次 ajax 调用 :(

【问题讨论】:

  • 您的问题中没有冒号的event {...} 是错字吗?
  • 是的,我应该说,该活动完美无缺。不幸的是,当我选择一个国家时,事件会触发两次......
  • 你为什么不订阅CountrySelected?
  • 我稍微扩展了我的问题:)
  • 所以如果我理解正确,你的问题是当你选择一个下拉菜单时你有一个无限循环?限制您的可观察量的速率怎么样?或者某种锁定机制来指定您的 observable 刚刚被触发并且不需要再次触发?

标签: javascript jquery knockout.js


【解决方案1】:

我有一种直觉,你问这个问题过于简单,但就目前而言,关于你的再现有两个要点:

  1. 您正在订阅 DOM 事件。不需要:改用基于视图模型的订阅。它会为您提供更多控制权并允许您对其进行单元测试。
  2. 您在更改Cities 下拉列表时调用IChanged,这没有任何意义。当用户更改城市时,为什么要更新可用城市列表?

无论如何,这是防止循环更新的一种方法:

function GoGetMyOptions(country) {
  console.log("Doing ajaxy stuff");
  return {
    done: function(callback) {
      if (country === "USA") callback(["New York", "L.A.", "Chicago"]);
      if (country === "GBR") callback(["London", "Manchester", "Leeds"]);
      if (country === "GER") callback(["Bonn", "Koln", "Hamburg"]);
    }
  };
}

function ViewModel() {
  var self = this;

  self.Countries = ko.observableArray([]);
  self.Cities = ko.observableArray([]);
  self.CountrySelected = ko.observable();
  self.CitySelected = ko.observable();
  
  self.CountrySelected.subscribe(function(newVal) {
    GoGetMyOptions(newVal).done(function(response) {
      self.Cities(response);
    });
  });

}

var vm = new ViewModel();

vm.Countries.push("USA", "GBR", "GER");

ko.applyBindings(vm);
<script src="https://cdnjs.cloudflare.com/ajax/libs/knockout/3.4.0/knockout-min.js"></script>

<select data-bind="options: Countries, value: CountrySelected"></select>
<select data-bind="options: Cities, value: CitySelected"></select>

正如您在控制台上看到的,更改城市时不会发生 Ajax 调用,只有更改国家/地区时才会发生。

【讨论】:

  • 我需要坐下来从一开始就更新我的问题,简化从来没有帮助哈哈但是,您提出了一些有助于清理我的代码的观点。我将事件更改添加到城市的原因是因为用户可以配置多个过滤器,我无法知道会有多少:)
  • @Heberda 如果您的实际问题与这个问题有很大的不同,您可以考虑创建一个新问题,并获得一些新的关注。
  • 也许我应该,我不喜欢垃圾邮件,虽然哈哈这给了我很多想法,我有工作代码,但后台有很多浪费的淘汰赛事件!跨度>
  • 这是一条很好的路线。如果您重新发布非常相似/几乎重复的问题,您往往会得到负面回应,但同样,tends to be frowned upon 也是一个不断变化的问题。你应该没问题,因为你显然已经付出了很多努力,这是非常感谢的。最终决定权在你 :-)
猜你喜欢
  • 2018-04-27
  • 1970-01-01
  • 2013-01-16
  • 1970-01-01
  • 1970-01-01
  • 2021-12-21
  • 2020-12-27
  • 1970-01-01
  • 2019-02-19
相关资源
最近更新 更多