0

After Commit 48 (Beta Candidate) i can't get observable array logic anymore. I know it has changed. I've read the changelog and been playing with new commit for some time but couldn't get it working. Helpers just don't update anymore. Any help appreciated.

Here is a simple example. Clicking "add friend" should call friends_names again.. but it doesn't anymore:

<!DOCTYPE html>
<html>
<head>
  <script src="http://code.jquery.com/jquery.js"></script>
  <script src="http://www.jsviews.com/download/jsviews.js"></script>
</head>
<body>

<div id="people"></div>

<script id="peopleTemplate" type="text/x-jsrender">
  <button id="add">Add person</button><br />
  {^{for people}}
   <div>
        Name: {{>name}}, 
        Friends: <span data-link="html{:~friends_names(#data.friends)}"></span>

        <button class="friend-add">add friend</button>
   </div>
  {{/for}}
</script>

<script>
var data = {
  people: [
    {
      name: "Adams",
      friends: [
        {name:'Petere'}, 
        {name:'Steve'}
      ]
    },
    {
      name: "Eugenia",
      friends: [
        {name:'Bob'}
      ]
    }
  ]
};

$.templates({ 
  peopleTmpl: "#peopleTemplate"
});

var friends_names = function(friends){
        friends = friends || []
        var names = []
        for (var i=0, l=friends.length; i<l; i++) {
            names.push(friends[i].name);
        }
        return '<b>' + names.join(', ') + '</b>';
    };

$.views.helpers({friends_names:friends_names});

$.templates.peopleTmpl.link("#people", data);

//debug
$.observable(data).observeAll(function (ev, obj) { console.log('change', obj); });

$("#add").on("click", function() {

  $.observable(data.people).insert({
    name: "Amos",
    friends: []
  });
})

$('#people').on('click', '.friend-add', function(e){
    e.preventDefault();

    var name = 'Some anonymous friend' + Math.floor((Math.random()*100)+1);

    var friends = $.view(this).data.friends;
    $.observable(friends).insert({
        name: name
    });
});

</script>
</body>
</html>

I know nested template can be used (not sure if it will solve the problem) but in real application there is much more logic in helper, thus nested template won't help.

gw128
  • 11
  • 2

1 Answers1

0

Yes, this is deliberate: See the commit note:

  • Data linking to arrays is simplified and more consistent. Now tags DO NOT automatically bind to arrays, and refresh when the array updates. {^{myTag path.to.array/}} will now update when the to.array property is update (property change) but not when the to.array itself changes observably. (array change). A tag should opt in to arraybinding either by deriving from the "for" tag - as in the 'range' sample: http://www.jsviews.com/#samples/tag-controls/range, or by following the using onAfterLink and onDispose to add/remove the onArrayChange handler, as in the {^{myWidget .../}} sample in the JsViews unit tests. This change relates to https://github.com/BorisMoore/jsviews/issues/158

Here is a really simple fix. If you include the array.length as a parameter (even if your helper function doesn't use it) then JsViews will respond to changes in the array length (which is a property change, not an array change) and will trigger a refresh for your helper: ~friends_names(friends, friends.length)

  {^{for people}}
   <div>
        Name: {{>name}}, 
        Friends: <span data-link="html{:~friends_names(friends, friends.length)}"></span>

        <button class="friend-add">add friend</button>
   </div>
  {{/for}}
BorisMoore
  • 8,444
  • 1
  • 16
  • 27
  • Thanks. Acutally in my application "friends" has deeper nested array. And helper should be called on it's change, friends count will stay unchanged, thus it won't refresh helper. Example: friends: { ['name': 'Name1', 'some_rels': [1,2,3,5]], ['name': 'Name2', 'some_rels': [5,6,3]] } After i update 'some_rels' helper should be triggered. One workaround is to add friends_update_time or friends_hash and update it every time, but then i don't see any use of observable anymore. – gw128 Jan 22 '14 at 09:20
  • You can use observeAll to do deep observing. A helper is a function, so it can't implicitly know all its dependencies. You can create a helper which is a computed observable on which you declare dependencies: http://borismoore.github.io/jsviews/demos/features/observability/computed-helper.html. But again those dependencies are propertyChange based. I don't know how your deep dependency worked previously since the friends parameter was not itself raising an arrayChange event. You can use observeAll then from there, change an observable flag or trigger an observable event... – BorisMoore Jan 22 '14 at 18:29