选择带有敲除绑定的更改事件,我怎么知道它是否是真正的更改


87

我正在构建一个权限UI,我有一个权限列表,每个权限旁边都有一个选择列表。权限由绑定到选择列表的可观察对象数组表示:

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

现在的问题是这样的:当UI首次填充时,将引发change事件。我调用ajax函数,获取权限列表,然后为每个权限项引发事件。这真的不是我想要的行为。我希望仅当用户确实在选择列表中为权限选择了新值时才引发它,我该怎么做?

Answers:


106

实际上,您想查找事件是由用户还是由程序触发的,并且很明显该事件将在初始化时触发。

淘汰赛的添加方法subscription在所有情况下都无济于事,原因是因为在大多数模型中都将像这样实现

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

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

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

并在permissionChanged功能中检测到事件

this.permissionChanged = function (obj, event) {

  if (event.originalEvent) { //user changed

  } else { // program changed

  }

}

5
我认为这应该标记为正确答案。我有问题所描述的确切场景,并且测试了将字符串作为select元素的键传递。但是,即使select的初始值与选项之一匹配,它仍会触发change事件。当我if在处理程序中实现此简单块时,一切都按预期工作。首先尝试此方法。谢谢@萨拉斯!
Pflugs 2015年

我喜欢区分用户更改和程序更改的概念。这在日常情况下很有用,尤其是在淘汰赛中,可观察物最可能在没有任何用户交互的情况下改变价值。
rodiwa

同意@Pflugs,区分对我有用的事件类型,这应该是公认的答案。
艾玛米德布鲁克

1
def应该是一个可以接受的答案...事件类型属性可以用于区分premissionChanged的触发
caniaskyouaquestion

1
还使用此方法来检测用户是否在更改选择而不是其他触发器。在我的情况下,通过“选项”绑定更新选项值触发了“更改”事件。
2017年

32

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

此外,更“淘汰”的方法是不使用事件处理程序,而是使用可观察对象和订阅。创建level一个可观察的对象,然后向其添加一个订阅,该订阅将在level更改时运行。


在挖掘了两个小时的原因之后,我的表单在页面加载后触发了“更改”事件,您猜是救了我。
萨米A 2015年1

您的回答给了我一个主意...我有意更改了来自url的类型,因此我的订阅函数将在页面加载时触发(我希望它处理url var,而不仅仅是我的下拉菜单触发更改时)。有没有那么简单的方法?
Jiffy

4

这里是一个解决方案,可以帮助解决这种奇怪的行为。除了找到一个按钮手动触发更改事件之外,我找不到更好的解决方案。

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

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
            }

        });

    }
  };

然后在您的选择数据绑定属性中添加:

changeSelectValue: yourSelectValue

哦...你的意思是喜欢保存按钮?..对我不好..我真的只需要这个就可以了:)
Guy Schaller

用更好的解决方案编辑答案(希望如此)。
Ingro 2012年

嘿Ingro,这被(错误地)标记为不是答案。我改写了您的第一句话,以使举报者不会意外地认为您是在提问。希望这可以帮助!:)
jmort253

@ jmort253:对不起,那是我的错。最好不要使用“我也有同样的问题”来回答,因为这似乎在询问您其他问题。相反,直接提供答案的解决方案并解释其工作原理。
澳洲航空94年重型车

1
是的,抱歉,我的错。这是我在stackoverflow上发布的第一个答案之一,并不知道所有规则。感谢您的编辑!
Ingro 2013年

3

我用这个自定义绑定(基于琴由RP尼迈耶,看他的回答这个问题),这可以确保数值正确的字符串转换为数字(由麦可思的解决方案建议):

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>

2

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


1

快速而肮脏,使用一个简单的标志:

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()中-事件是异步的,因此当applyBindings()已经返回时,最后一个可能仍在等待处理。


嗨,谢谢你的答复,这对我来说是行不通的,因为当dom准备好时,我会调用ko.applyBindings,但是稍后会在模型中填充我的权限a,因此该标记为true,但是问题仍然会发生。
guy schaller 2012年

0

我有一个类似的问题,我刚刚修改了事件处理程序以检查变量的类型。仅在用户选择一个值之后才设置类型,而不是在首次加载页面时设置。

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

这似乎对我有用。


0

用这个:

this.permissionChanged = function (obj, event) {

    if (event.type != "load") {

    } 
}

0

试试这个:

self.GetHierarchyNodeList = function (data, index, event)
{
    debugger;
    if (event.type != "change") {
        return;
    }        
} 

event.type == "change"
event.type == "load" 

第二个参数不是索引,对我来说是事件。
sairfan

@sairfan向该函数添加一些参数,并使用调试器查找从哪个参数获取事件
Chanaka Sampath

-1

如果您使用的是淘汰赛,请使用可观察到的功能淘汰赛的关键功能。
使用ko.computed()method并在该函数中执行并触发ajax调用。

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.