daveycroqet
daveycroqet

Reputation: 2727

Using Knockout observables derived from JSON to update the view dynamically

Hopefully this isn't bad practice, but I am trying to understand Knockout observables within the context of my previous question.

I want to update the view with 'red flower' or 'blue sky', depending on which button is clicked. Let's presume the JSON will be static. How can I go about using observables to update the view while only applying my bindings a single time?

Fiddle:

https://jsfiddle.net/ft8a6jbk/3/

HTML:

<button class="blue">Blue</button>
<button class="red">Red</button>

<div data-bind="text: name"></div>
<div data-bind="text: things()[0].item1"></div>

<script>
  ko.applyBindings(viewModel);
</script>

JS:

var data = {
  "colors": [{
    "name": "blue",
    "things": [{
      "item1": "sky",
      "item2": "ocean",
    }, ]
  }, {
    "name": "red",
    "things": [{
      "item1": "flower",
      "item2": "sun",
    }, ]
  }, ]
};

$('.blue').click(function() {
  var viewModel = ko.mapping.fromJS(data.colors[0]);
});

$('.red').click(function() {
  var viewModel = ko.mapping.fromJS(data.colors[1]);
});

Upvotes: 0

Views: 83

Answers (1)

Tomalak
Tomalak

Reputation: 338376

How can I [...] while only applying my bindings a single time?

Like this:

function Sample(data) {
  var self = this;
  
  self.colors = ko.observableArray();
  self.currentColor = ko.observable();
  
  ko.mapping.fromJS(data, {}, self);
}

var sample = new Sample({
  "colors": [{
    "name": "blue",
    "things": ["sky", "ocean"]
  }, {
    "name": "red",
    "things": ["flower", "sun"]
  }]
});

ko.applyBindings(sample);
<script src="https://cdnjs.cloudflare.com/ajax/libs/knockout/3.2.0/knockout-min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/knockout.mapping/2.4.1/knockout.mapping.min.js"></script>

<div data-bind="foreach: colors">
  <button data-bind="text: name, click: $root.currentColor"></button>
</div>

<div data-bind="with: currentColor">
  <h4 data-bind="text: name"></h4>
  <div data-bind="foreach: things">
    <span data-bind="text: $data" />
  </div>
</div>

Notes:

  • Don't write jQuery event handlers. Remove jQuery from your knockout code entirely. The two exceptions to this rule are: Using Ajax (since knockout has no Ajax functions) and writing custom binding handlers. Anything else, most prominently DOM manipulation, should be governed by Knockout completely.
  • An observable is a function. You can use it as an event handler, like I did above in the click binding. Here is how this works:
    1. Knockout passes the context data, in this case a single "color" item, to the event handler function, in this case the currentColor observable.
    2. When an observable is called with a value, it stores that value.
    3. Effect: Instant event handler and application state storage - without writing a single function yourself.

Upvotes: 2

Related Questions