jsviews

Jsviews tree control raises second click event after expanding


I'm trying to modify the tree control example so that it nests ul's inside an li, this is my template:

template:
            '<li>' +
                '{{if folders && folders.length}}' +
                    '<span class="toggle">{^{:expanded ? "-" : "+"}}</span>' +
                '{{else}}' +
                    '<span class="spacer">&bull;</span>' +
                '{{/if}}' +
                '{{>name}}' +
                '{^{if expanded}}' +
                    '<ul>' +
                    '{{for folders}}' +
                        '{^{tree/}}' +
                    '{{/for}}' +
                    '</ul>' +
                '{{/if}}' +
            '</li>',

And my tag is:

{^{tree _data/}}

This produces the desired html - but also raises a second click event which subsequently collapses the just expanded list items?

Any help appreciated, thanks.


Solution

  • This is because you have combined two <li>s into one, and the event bubbling of the click event is now triggering other toggle events on tree nodes higher up. (Before, the self.contents("li").first() selector was ensuring that a bubble click event from deeper down was not captured. But now deeper nodes are under the same li as the parent nodes.)

    So one fix is to prevent bubbling. Return false from the handler (or call event.stopPropagation()).

    self.contents("li")
      .on("click", ".toggle", function() {
        self.toggle();
        return false;
      });
    

    Another is to associate the click event with the span, not the li, so it doesn't find multiple .toggle targets:

    var self = this;
    self.contents("li").find(".toggle")
      .on("click", function() {
        self.toggle();
      });
    

    Another alternative is to use the {{on}} tag binding for the click handler. In fact the whole implementation is then simpler:

    $.views.tags({
      tree: {
        template: '<li>' +
          '{{if folders && folders.length}}' +
            '<span data-link="{on ~tag.toggle} {:expanded ? \'-\' : \'+\'}" class="toggle"></span>' +
          '{{else}}' +
            '<span class="spacer">&bull;</span>' +
          '{{/if}}' +
          '{{>name}}' +
          '{^{if expanded}}' +
            '<ul>' +
              '{{for folders}}' +
                '{{tree/}}' +
              '{{/for}}' +
            '</ul>' +
          '{{/if}}' +
        '</li>',
    
        //METHODS
        toggle: function() {
          var data = this.tagCtx.view.data;
          $.observable(data).setProperty("expanded", !data.expanded);
        }
      }
    });
    

    I will probably switch the sample to take this approach...