Reputation: 43
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
Upvotes: 4
Views: 1368
Reputation: 1074238
Two issues:
You're recreating your observable in changeText
. You need to remove the this.textFlag = ko.observable(false);
line. You've already done that bit.
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>
Upvotes: 2
Reputation: 99
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.
Upvotes: -1
Reputation: 5323
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.
Upvotes: 2