简体   繁体   中英

KnockoutJS - data-bind wont change text after button click

I have been struggling for a few days with knockout data binding. The simple yet very annoying example of problem that I struggle with is down below.

I have a simple ViewModel class with a method that changes boolean from false to true. Knockout does bind with HTML on page load, but there seems to be a problem with data bind on click event.

Observable does change when I debug the code, but View stays the same.

Whole code and (not)working example are down below.

 function ViewModel (data) { var self = this; this.textFlag = ko.observable(false); this.changeText = function (eventID, panelStatus) { this.textFlag = ko.observable(false); if(eventID == 1) this.textFlag(panelStatus); } } var viewModel = new ViewModel(); ko.applyBindings(viewModel); 
 <script src="https://cdnjs.cloudflare.com/ajax/libs/knockout/3.4.2/knockout-min.js"></script> <h1 data-bind="text: textFlag() === true"></h1> <button data-bind="click: changeText(1, true)">Button</button> 

See example on jsfiddle

Two issues:

  1. You're recreating your observable in changeText . You need to remove the this.textFlag = ko.observable(false); line. You've already done that bit.

  2. Your click handler is defined incorrectly. Remember that KO takes your bindings and effectively creates an object initializer out of them. Let's look at the one that would create:

     { click: changeText(1, true) } 

    See the problem? That calls changeText(1, true) and assigns the result of the call to click . Instead, you want to provide a function reference, so click can call the function.

    (Obviously, what KO actually does is more complicated than that, with lots of with wrappers, but eventually that's what it does.)

Once you remove the errant line from changeText , you could do this:

<button data-bind="click: changeText.bind($data, 1, true)">Button</button>

Live Example:

 function ViewModel (data) { var self = this; this.textFlag = ko.observable(false); this.changeText = function (eventID, panelStatus) { if(eventID == 1) this.textFlag(panelStatus); } } var viewModel = new ViewModel(); ko.applyBindings(viewModel); 
 <script src="https://cdnjs.cloudflare.com/ajax/libs/knockout/3.4.2/knockout-min.js"></script> <h1 data-bind="text: textFlag() === true"></h1> <button data-bind="click: changeText.bind($data, 1, true)">Button</button> 

...but it may be better to define a function on the viewmodel that uses 1, true :

this.changeText1True = function() { return this.changeText(1, true); };

...and call that:

<button data-bind="click: changeText1True">Button</button>

(Obviously, use a better name.)

Live Example:

 function ViewModel (data) { var self = this; this.textFlag = ko.observable(false); this.changeText = function (eventID, panelStatus) { if(eventID == 1) this.textFlag(panelStatus); } this.changeText1True = function() { return this.changeText(1, true); } } var viewModel = new ViewModel(); ko.applyBindings(viewModel); 
 <script src="https://cdnjs.cloudflare.com/ajax/libs/knockout/3.4.2/knockout-min.js"></script> <h1 data-bind="text: textFlag() === true"></h1> <button data-bind="click: changeText1True">Button</button> 

You are redefining this.textFlag variable, thus breaking the binding. All you have to do is update its value using this.textFlag(panelStatus); like this :

 function ViewModel(data) { var self = this; this.textFlag = ko.observable(false); this.changeText = function(eventID, panelStatus) { if (eventID == 1) { this.textFlag(panelStatus); } } } var viewModel = new ViewModel(); ko.applyBindings(viewModel); 
 <script src="https://cdnjs.cloudflare.com/ajax/libs/knockout/3.4.2/knockout-min.js"></script> <h1 data-bind="text: textFlag() === true"></h1> <button data-bind="click: function () { changeText(1, true) }">Button</button> 

As stated in TJ Crowder answer you also have to either wrap your call to your function inside another anonymous function as seen in docs or create another function using bind like suggested.

 function ViewModel (data) { var self = this; self.textFlag = ko.observable(false); self.changeText = function (eventID, panelStatus) { if(eventID === 1) { self.textFlag(panelStatus); } } } var viewModel = new ViewModel(); ko.applyBindings(viewModel); 
 <script src="https://cdnjs.cloudflare.com/ajax/libs/knockout/3.4.2/knockout-min.js"></script> <h1 data-bind="text: textFlag"></h1> <button data-bind="click: changeText.bind($data, 1, true)">Button</button> 

Made some change to your code.

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