改变select与淘汰赛的绑定事件,我怎么知道它是否是一个真正的变化

我正在构build权限用户界面,我有一个权限列表与每个权限旁边的select列表。 权限由绑定到select列表的可观察数据对象表示:

<div data-bind="foreach: permissions"> <div class="permission_row"> <span data-bind="text: name"></span> <select data-bind="value: level, event:{ change: $parent.permissionChanged}"> <option value="0"></option> <option value="1">R</option> <option value="2">RW</option> </select> </div> </div> 

现在问题是这样的:当用户界面第一次填充时,更改事件会被触发。 我打电话给我的ajax函数,获取权限列表,然后为每个权限项目引发事件。 这真的不是我想要的行为。 我希望只有在用户真正为select列表中的权限选取新值时才会提出这个问题 ,我该怎么做?

这只是一个猜测,但我认为这是因为level是一个数字。 在这种情况下, value绑定将触发一个change事件来更新string值的level 。 您可以通过确保level是一个string来解决这个问题。

另外,这样做的更多的“敲除”方法是不使用事件处理程序,而是使用可观察和订阅。 使level成为一个可观察的,然后添加一个订阅,它会随着level变化而运行。

实际上, 你要查找事件是由用户还是程序触发的 ,而且显然这个事件在初始化的时候会触发。

添加subscription的淘汰办法在所有情况subscription都无济于事,为什么呢,因为在这个模型的大部分内容都会这样实施

  1. 用未定义的数据初始化模型,只是结构(actual KO initilization)初始化(actual KO initilization)
  2. 用初始数据更新模型(logical init like load JSON , get data etc)
  3. 用户交互和更新

我们要捕获的实际步骤是在3中进行更改,但是在第二步中, subscription将会被调用,所以更好的方法是添加到事件更改

  <select data-bind="value: level, event:{ change: $parent.permissionChanged}"> 

并在permissionChanged函数中检测到事件

 this.permissionChanged = function (obj, event) { if (event.originalEvent) { //user changed } else { // program changed } } 

我使用这个自定义绑定(基于RP Niemeyer的这个小提琴,请参阅他对这个问题的回答),它确保数值正确地从string转换为数字(如Michael Best的解决scheme所build议的):

使用Javascript:

 ko.bindingHandlers.valueAsNumber = { init: function (element, valueAccessor, allBindingsAccessor) { var observable = valueAccessor(), interceptor = ko.computed({ read: function () { var val = ko.utils.unwrapObservable(observable); return (observable() ? observable().toString() : observable()); }, write: function (newValue) { observable(newValue ? parseInt(newValue, 10) : newValue); }, owner: this }); ko.applyBindingsToNode(element, { value: interceptor }); } }; 

HTML示例:

 <select data-bind="valueAsNumber: level, event:{ change: $parent.permissionChanged }"> <option value="0"></option> <option value="1">R</option> <option value="2">RW</option> </select> 

这是一个解决scheme,可以帮助这种奇怪的行为。 我找不到比放置button手动触发更改事件更好的解决scheme。

编辑:也许像这样的自定义绑定可以帮助:

 ko.bindingHandlers.changeSelectValue = { init: function(element,valueAccessor){ $(element).change(function(){ var value = $(element).val(); if($(element).is(":focus")){ //Do whatever you want with the new value } }); } }; 

并在您select的数据绑定属性中添加:

 changeSelectValue: yourSelectValue 

快速和肮脏,利用一个简单的标志:

 var bindingsApplied = false; var ViewModel = function() { // ... this.permissionChanged = function() { // ignore, if flag not set if (!flag) return; // ... }; }; ko.applyBindings(new ViewModel()); bindingsApplied = true; // done with the initial population, set flag to true 

如果这不起作用,请尝试将最后一行包装在setTimeout()中 – 事件是asynchronous的,所以当applyBindings()已经返回时,最后一行仍然是挂起的。

如果使用observable而不是原始值,则select不会在初始绑定时引发更改事件。 您可以继续绑定到更改事件,而不是直接订阅observable。

我有一个类似的问题,我只是修改事件处理程序来检查variables的types。 types仅在用户select一个值之后设置,而不是在页面第一次加载时设置。

 self.permissionChanged = function (l) { if (typeof l != 'undefined') { ... } } 

这似乎为我工作。

如果您正在使用Knockout,请使用可观察function敲除的关键function。
使用ko.computed()方法并在该函数内执行并触发ajax调用。