Shouldz
Shouldz

Reputation: 58

Knockout observable array doesn't re-render my list

I need some help here: https://jsfiddle.net/vhaurnpw/

I want to do a simple list, which is filterable by the input on top and updates itself..

JS/Knockout:

var viewModel = {
    query: ko.observable(''),
    places: ko.observable(data),

    search: function(value) {
        viewModel.places = [];
        console.log(value)

        for (var i = 0; i < data.length; i++) {

            if(data[i].name.toLowerCase().indexOf(value.toLowerCase()) >= 0) {
                viewModel.places.push(data[i]);
            }
                console.log(viewModel.places);
        }
    }
};

viewModel.query.subscribe(viewModel.search);

ko.applyBindings(viewModel);

HTML:

<form acion="#" data-bind="submit: search">
<input placeholder="Search" type="search" name="q" data-bind="value: query, valueUpdate: 'keyup'" autocomplete="off">
</form>

<ul data-bind="foreach: places">
  <li>
     <span data-bind="text: name"></span>
  </li>
</ul>

List will be rendered, but it when you type something, it doesn't show you the result.

Instead when you lookup the console, you will see the console.log and it updates just fine!

so how do i refresh my HTML? :(

Upvotes: 1

Views: 865

Answers (1)

Abhinav Galodha
Abhinav Galodha

Reputation: 9908

There are following issues in your code.

  1. places needs to be an ObservableArray and not an Observable so that you can track the addition/removal from the Observable Array. So, change code From places: ko.observable(data) To places: ko.observableArray(data),
  2. viewModel.places is function, so when you assign another value like viewModel.places = [], it is assigning an empty array to the viewModel.places. In order to modify the value of the viewModel.places, you need to call it as a function like viewModel.places([]);

Note: Your code doesn't add the data back in case the textbox is cleared, I hope you got the solution to the problem and you can resolve this issue as well.

Complete Working Code:

var data = [
			{ name: 'Isartor'},
			{ name: 'Sendlinger Tor'},
			{ name: 'Marienplatz'},
			{ name: 'Stachus'},
			{ name: 'Bayerischer Rundfunk'},
			{ name: 'Google München'},
			{ name: 'Viktualienmarkt'},
			{ name: 'Museumsinsel'},
			{ name: 'Tierpark Hellabrunn'},
			{ name: 'Allianz Arena'},
			{ name: 'Olympia-Park'},
			{ name: 'Flaucher-Insel'}
					];

var viewModel = {
		query: ko.observable(''),
		places: ko.observableArray(data),

		search: function(value) {
			viewModel.places([]);
			console.log(value)

			for (var i = 0; i < data.length; i++) {

				if(data[i].name.toLowerCase().indexOf(value.toLowerCase()) >= 0) {
					viewModel.places.push(data[i]);
				}
					console.log(viewModel.places);
			}
		}
};

viewModel.query.subscribe(viewModel.search);

ko.applyBindings(viewModel);
<script src="https://cdnjs.cloudflare.com/ajax/libs/knockout/3.2.0/knockout-min.js"></script>
<form acion="#" data-bind="submit: search">
  <input placeholder="Search" type="search" name="q" data-bind="value: query, valueUpdate: 'keyup'" autocomplete="off">
</form>

<ul data-bind="foreach: places">
    <li>
      <span data-bind="text: name">asd</span>
    </li>
</ul>

Upvotes: 2

Related Questions