简体   繁体   中英

Calling jQuery .trigger('change') on a hidden value breaks knockout dependent observable

There's a bit of story behind how we ran into this... Basically, we were calling trigger('change') on all of our form inputs to let other knockout observables know their value had been reset. But I really think it's a bug in Knockout. Asking here to see if anyone else has run into it (and StackOverflow is a much nicer interface than Knockout's google forums).

So if you have a hidden input who's value is data-bound to a computed observable and you call jQuery's trigger('change') on it, it wipes out the observable. If you drill into the code, you can see that on the view model object, the member object is replaced with a string of the last value on the computed observable before you triggered the change event.

JS fiddle showing the breakage in action: http://jsfiddle.net/2VvvE/1/

It uses console.log to output the object, so be warned if you try a browser without console ( cough IE). You can see that the dependent observable is working fine until you hit the 'Break It' button, after which, the value stops updating and subsequent presses output the same thing. If you comment out the line with the trigger('change') on it and re-run the fiddle, you can see that it continues to work after each button press.

Apologies for not asking a real question - we already figured a work around where we only call trigger('change') on inputs that aren't hidden (pretty straightforward jquery selector in case anyone is curious):

$("#"+this.id+" form").each(function() {
    $(this).validate().resetForm();
    this.reset();

    // Do some actions on all the inputs, then filter before calling the trigger
    $(this).find('input,select').data('valid','true').filter(':not(:hidden)').trigger('change');
    $(this).find('label,legend').removeClass('validated-error');
});

But I wanted a verdict: Knockout bug? Or am I doin' it wrong?

You should not bind a normal computed observable against a read/write binding like value . This is causing it to get overwritten in your model.

If you have to you can use a writeable computed observable . In this case you could even have a blank write function: http://jsfiddle.net/rniemeyer/2VvvE/2/

The actual answer though is that you really don't need to be triggering the change events on the fields. A better way to handle this is to do it from your view model. On any observable or computed observable you can call the valueHasMutated() function to notify all subscribers again with the latest value.

myObservable.valueHasMutated()

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM