0
votes

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.

1

1 Answers

0
votes

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}}