I have an observableArray that won't update in the HTML even though I can log it to the console and see it change.
The example below has a list of people (people). I search that list and try to add the results to a new observableArray (searchResult) that is bound to an unordered list. This list element is never updated, though the console shows that the correct entries from people are found. Why aren't the search results showing in the HTML?
Here is my code (also available on JSFiddle):
function AppViewModel() {
var self = this;
self.people = ko.observableArray([{
fName: "Thomas",
lName: "Edison"
}, {
fName: "Sally",
lName: "Salputrio"
}, {
fName: "Edward",
lName: "Sparkleshine"
}, {
fName: "Jacob",
lName: "Wolfsson"
}]);
self.searchResult = ko.observableArray([]);
self.searchFieldKo = ko.observable("");
self.submitSearch = function () {
if (self.searchFieldKo() != "") {
self.searchResult().length = 0;
$.each(self.people(), function (pKey, pObj) {
$.each(pObj, function (pProp, pValue) {
if (pValue.toString().toLowerCase().indexOf(self.searchFieldKo().toLowerCase()) >= 0) {
self.searchResult().push(self.people()[pKey]);
console.log(self.searchResult());
}
})
})
} else {
alert("Please type something.");
}
}
}
ko.applyBindings(new AppViewModel());
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/1.8.3/jquery.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/knockout/2.2.1/knockout-min.js"></script>
<fieldset class="span20 offset2">
<legend>Search Me!</legend>
<form class="form-search">
<div class="input-append">
<input type="text" data-bind="value: searchFieldKo, valueUpdate: 'afterkeydown'" class="input-medium search-query" id="searchField">
<button class="btn" data-bind="click: submitSearch">search</button>
</div>
</form>
<h5> Search Results:</h5>
<ul data-bind="foreach: searchResult" class="unstyled">
<li> <span data-bind="text: fName"></span> <span data-bind="text: lName"></span>
</li>
</ul>
<h5>People List:</h5>
<ul data-bind="foreach: people" class="unstyled">
<li> <span data-bind="text: fName"></span> <span data-bind="text: lName"></span>
</li>
</ul>
</fieldset>
You have an unnecessary set of parenthesis in
self.searchResult().push(self.people()[pKey]);
it should be
self.searchResult.push(self.people()[pKey]);
Demo JSFiddle.
Because when you write self.searchResult() you are accessing the underlaying array in the observable. And when you push into that array KO won't be notified about the changes so you need to use the push method on the observableArray itself.
By the way Knockout has a great set of useful array helpers which could simplify your filtering logic.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With