I have a knockout observable array whose value assignment changes after a set value of time but do not see this reflecting in the view. Could someone tell where I am doing it wrong? I would expect the output to show
• GRE 1111 • TOEFL 111
but it shows
• GRE2 222 • TOEFL2 22
jsFiddle link: https://jsfiddle.net/4r37x9y5/
HTML:
console.clear();
function viewModel() {
this.plans = ko.observableArray([]);
var plans1 = [
{ id: 'GRE', count: '1111' },
{ id: 'TOEFL', count: '111' },
];
var plans2 = [
{ id: 'GRE2', count: '222' },
{ id: 'TOEFL2', count: '22' },
];
this.plans = plans2;
//this.plans = plans1;
setTimeout(function(){
console.log("In timeout before assigning plans");
this.plans = plans1;
console.log(this.plans);
}, 2000);
}
ko.applyBindings(viewModel());
// The above line equals:
// viewModel(); // updates window object and returns null!
// ko.applyBindings(); // binds window object to body!
<script src="https://cdnjs.cloudflare.com/ajax/libs/knockout/3.4.2/knockout-min.js"></script>
<div class="panel panel-default">
<ul data-bind="foreach: plans" class="list-group">
<li class="list-group-item">
<span data-bind="text: id"></span>
<span data-bind="text: count"></span>
</li>
</ul>
</div>
There are couple of issues here. As mentioned by you in the comments, you are not binding an object with observables. You are simply adding a global variable plans
. If knockout can't find a property in the viewModel, it will use the window object's property. That's why it works the first time
viewModel
as a constructor function and use new viewModel()
to create an object or an instance.this.plans(plans1)
. If you set this.plans = plans2
, it will simply overwrite the observable with a simple array without the subscribers to update the UI when the property changesthis
inside setTimeout
. Either by creating a self = this
variable outside or using an arrow function as a callbackfunction viewModel() {
this.plans = ko.observableArray([]);
var plans1 = [{ id: "GRE", count: "1" }, { id: "TOEFL", count: "1" }];
var plans2 = [{ id: "GRE2", count: "2" }, { id: "TOEFL2", count: "2" }];
this.plans(plans2) // call it like a function
setTimeout(() => {
console.log("In timeout before assigning plans");
this.plans(plans1)
}, 2000);
}
ko.applyBindings(new viewModel()); // new keyword to create an object
<script src="https://cdnjs.cloudflare.com/ajax/libs/knockout/3.4.2/knockout-min.js"></script>
<ul data-bind="foreach: plans">
<li>
<span data-bind="text: id"></span>
<span data-bind="text: count"></span>
</li>
</ul>