可以将文章内容翻译成中文,广告屏蔽插件可能会导致该功能失效(如失效,请关闭广告屏蔽插件后再试):
问题:
I have a simple checkbox which has its value adjusted by a bit of infrastructure that I'm writing to persist state in localStorage. I am aware that this would normally be done by setting the viewModel but the infrastructure is unaware of any knockout bindings and has no access to them.
I didn't think this would be a problem as I assumed that knockout was running off the 'change' event, however $checkbox.prop('checked', true).trigger('checked')
fails to trigger my observable. Even using the click event directly doesn't get me quite what I need.
What events does knockout wire to? How do I get it to read the state of the control?
jsbin showing this weird behavior here. Try selecting the checkbox directly versus clicking the button.
回答1:
I found a better way of doing that. Just put this code inside of your domready event:
$("input:checkbox").bind('change', function () {
$(this).triggerHandler('click');
});
回答2:
Knockout bindings don't really work in the way you are thinking.
Check out: http://knockoutjs.com/documentation/custom-bindings.html
Here is one solution you can use, no jQuery, no custom binding.
Your html will stay the same.
var m = {
isChecked: ko.observable(false),
infrastructureUpdatesCheckbox: function() {
this.isChecked( this.isChecked() === true ? false : true);
}
};
ko.applyBindings(m);
回答3:
you should change checkbox' checked status via your view model:
var m = {
isChecked: ko.observable(false)
//,infrastructureUpdatesCheckbox: function() {
//$chk = $(':checkbox');
//$chk
// .prop('checked', !$chk.prop('checked'))
// .trigger('change');
//this.isChecked(!this.isChecked()); // this - is your view model
}
};
here is updated version:
function InfrastructureUpdatesCheckbox(){
var $cb = $(':checkbox');
var cb = $cb[0];
cb.checked = !cb.checked; // manually change checked status
$cb.triggerHandler('click'); // run all event handlers bound to 'click' event
}
I guess the issue is related to checkboxes (radio buttons) only. Other controls should behaive correctly when you trigger events manually.
回答4:
You've probably already found a solution to your problem but this might help someone else.
I have had the exact same problem. What I did was use a pub-sub pattern and have my component trigger its own change event. What you could then do is to have the instance of the infrastructure component that needs to update the model subscribe to that event and then update your model. Better still your model can subscribe to the event, that way your model knows about the infrastructure component rather than the other way around
That way your infrastructure component does not need to know about ko and you can re-use it anywhere else. I am sure it's only a matter of time before you find other uses for it if you plan to re-use that component.
Hope this helps (sorry there is no code as I can't post clients code on SO, but if anyone wants an example just say so and I'll do a jsfiddle to illustrate.
回答5:
In my case this turned out to be related to a jquery bug. I took to the github knockout issue tracker to track this down; see here.
Ultimately I ended up doing this in my component:
var isjQueryOld = /^(0|1)\.[0-8]\./.test($.fn.jquery); // <=1.8.*
var toggleCheckbox = isjQueryOld ? jQueryOldToggleCheckbox : function($el) { $el.trigger('click') } //https://github.com/knockout/knockout/issues/987
function jQueryOldToggleCheckbox($el) {
//This should be simple right? See http://stackoverflow.com/a/8595601/5056
//and "simulating events to adjust knockout models" jasmine spec
//all this is nessessary to get everything working with knockout
var changeTo = !$el.prop('checked');
if(changeTo)
$el.attr('checked', true);
else
$el.removeAttr('checked');
$el.trigger('click');
$el.prop('checked', changeTo);
}
and in my code
toggleCheckbox($el);
回答6:
I don't know what event knockout is listening for, you could probably wade into the source itself and figure it out, but one solution would be to use a custom binding. In the init
for the custom binding you can set whatever handlers you want for whatever events you want to capture (such as changed
) and use that to force you binding to run update
.
回答7:
I've spend hours today falling into on-click loop with checked & click approach, trying ko.observable, pureComputed write or even infrastructureUpdatesCheckbox without success too long to explain to anybody who pay for my work why I'm not able to check the radio button in the damn Knockout. Unfortunately my context (Magento 2 checkout with purchased plugins) didn't allow me to implement valid view model so finally I've managed to solve the issue with simple hack to add second input type="radio" and show it on click:
selectRadioPayment: function (obj, event, method) {
this.selectPaymentMethod(obj, event, method);
$('.ko-payment-selector').show();
$('#p_method_' + method).hide();
$('#p_method_' + method).closest('.radio-payment-selector').show();
},
renderedPaymentMethods: function() {
if(quote.paymentMethod) {
var selectedMethod = quote.paymentMethod().method;
$('#p_method_' + selectedMethod).hide();
$('#p_method_' + selectedMethod).closest('.radio-payment-selector').show();
}
},
<input class="radio-payment-selector" type="radio" class="hidden" checked />
<input class="ko-payment-selector" type="radio" name="payment[method]" class="radio" event: {change: function(data, event){$parent.selectRadioPayment(data, event, $data.method)}}"/>
I hope it would help someone someday.