Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Knockout.js Make every nested object an Observable

I am using Knockout.js as a MVVM library to bind my data to some pages. I'm currently building a library to make REST calls to a web service. My RESTful web service returns a simple structure:

{     id : 1,     details: {         name: "Johnny",         surname: "Boy"     } } 

I have an observable main parent, myObject. When I do

myObject(ko.mapping.fromJS(data)) 

the observables in myObject are:

  • id
  • name
  • surname

How can I make details (and theoretically any object in the structure an observable)? I need this behavior so that i can set a computed observable on details and get noticed as soon as any of the internal data changes.

I have set up a basic recursive function which should do the trick. It doesn't, of course, myObject.details doesn't become an observable.

// Makes every object in the tree an observable. var makeAllObservables = function () {     makeChildrenObservables(myObject); }; var makeChildrenObservables = function (object) {     // Make the parent an observable if it's not already     if (!ko.isObservable(object)) {         if ($.isArray(object))             object = ko.observableArray(object);         else             object = ko.observable(object);     }     // Loop through its children     for (var child in object()) {         makeChildrenObservables(object()[child]);     } }; 

I'm pretty sure it's something about incorrect references, but how can I solve this? Thank you.

like image 577
frapontillo Avatar asked May 11 '12 16:05

frapontillo


People also ask

How do I set observable value in knockout?

To create an observable, assign the ko. observable function to the variable. A default value can be specified in the constructor of the call. Knockout then converts your variable into a function and tracks when the value changes, in order to notify the UI elements associated with the variable.

Is knockout observable?

An observable is useful in various scenarios where we are displaying or editing multiple values and require repeated sections of the UI to appear and disappear as items are inserted and deleted. The main advantage of KO is that it updates our UI automatically when the view model changes.

Is knockout js easy?

KnockoutJS library provides an easy and clean way to handle complex data-driven interfaces. One can create self-updating UIs for Javascript objects. It is pure JavaScript Library and works with any web framework. It's not a replacement of JQuery but can work as a supplement providing smart features.

What is observable array in knockout JS?

If you want to detect and respond to changes of a collection of things, use an observableArray . This is useful in many scenarios where you're displaying or editing multiple values and need repeated sections of UI to appear and disappear as items are added and removed.


2 Answers

I would use the knockout mapping plugin.

var jsonData = {     id : 1,     details: {         name: "Johnny",         surname: "Boy"     } }  var yourMapping = {     'details': {         create: function(options) {             return Details(options.data);         }     } }  function Details(data) {     ko.mapping.fromJS(data, {}, this); }  function YourObjectName() {     ko.mapping.fromJS(jsonData, yourMapping, this); } 

This will create your object hierarchy with all of the children as observables.

like image 114
Paolo del Mundo Avatar answered Oct 12 '22 23:10

Paolo del Mundo


I don't think knockout has a built-in way to observe changes to child elements. If I understand your question, when someone changes the name you want a change to details as an entity to be noticed. Can you give a concrete example of how you would use this? Would you use a subscription to the details observable to perform some action?

The reason your code doesn't make details an observable is because javascript is pass by value, so changing the value of the 'object' argument in your function doesn't change the actual value you passed, only the value of the argument inside your function.

Edit

If changes will automatically propagate to the parents, this should make all children observable I think, but your root that you pass the first time should already be an observable.

// object should already be observable var makeChildrenObservables = function (object) {     if(!ko.isObservable(object)) return;      // Loop through its children     for (var child in object()) {         if (!ko.isObservable(object()[child])) {             object()[child] = ko.observable(object()[child]);         }         makeChildrenObservables(object()[child]);     } }; 
like image 23
Jason Goemaat Avatar answered Oct 13 '22 01:10

Jason Goemaat