Search code examples
jsviews

Deep chained paths with compiled view model objects


Given a compiled view model hierarchy instantiated with this data:

"applications":[
  {
     "application_id":1,
     "name":"Test Application 1",
     "description":"An Application For Testing",
     "settings":[
        {
           "name":"Application 1 Setting Key 1",
           "value":"Application 1 Setting Value 1"
        }
     ],
     "projects":[
        {
           "project_id":1,
           "name":"Test Project 1",
           "description":"A project for testing 1",
           "settings":[
              {
                 "name":"Project 1 Setting Key 1",
                 "value":"Project 1 Setting Value 1"
              }
           ]
        }
     ]
  }
]

I'm having difficulty tapping into the observables at levels farther down in the tree.

No problem observing changes to properties of an application:

$.observe(data.applications(), ".[]^*", ...

But how about changes to properties of a setting under an application? These are all FAILs:

$.observe(data.applications().settings(), ".[]^*", ...
$.observe(data.applications(), ".settings.[]^*", ...
$.observe(data.applications(), ".settings().[]^*", ...  

I see the documentation specifically mentions parentheses will not work in chained paths like the last example so there wasn't much hope for that last one.

I seem to be able to get away with this:

$.observe(data.applications(), ".[]._settings.[]^*", ...

and if that's the only way please confirm, but the underscore makes me feel like I've tapped into underlying/protected/unofficial representation of data path. Any other way to chain compiled vm paths?


Solution

  • Given that applications() returns an array, as does settings(), you can't write:

    $.observe(data.applications().settings(), "[]^*", ...
    

    If you want to target a particular application, such as data.applications()[0], you could write:

    $.observe(data.applications()[0].settings(), "[]^*", ...
    

    If you want to target all the settings properties under any application, you can write:

    $.observe(data.applications(), "[]._settings.[]^*", ...
    

    You are right that _settings is supposed to be 'internal'. The intended design was indeed to let you write:

    $.observe(data.applications(), "[].settings.[]^*", ...
    

    but there is a currently a bug which prevents this from working. An upcoming update will either fix this bug, or propose a slightly different pattern. For now it would be better to stay with _settings, which will at any rate continue to work after the next update. Look out too, after the next update, for possible new documentation topics on the [].* wild cards and other related features...

    BTW if you want to listen to changes after modifying the data hierarchy higher up (for example the applications() array - which you might change using the merge() feature for VMs), then you will need to put a ^ at an appropriate level in the path, to listen to any changes below that level. For example you can write

    $.observe(data.applications(), "[]^_settings.[].*", ...
    

    or

    $.observe(data.applications(), "^[]._settings.[].*", ...
    

    or

    $.observe(data, "_applications^[]._settings.[].*", ...
    

    Another option is the ** wild card - which you can use at any level to show all changes below that level:

    $.observe(data.applications(), "**", ...
    

    or

    $.observe(data, "**", ...
    

    or

    $.observe(data, "_applications^[].**", ...