1

I recently inherited an application that relies heavily on Backbone.js. My application overrides the Backbone.sync() function to work with Qt (allowing the application perform AJAX requests in a browser embedded in a desktop application); so, it is preferred that Backbone is used as much as possible for AJAX.

I would like to use the jQuery Treeview plugin here and use Backbone to interact with my API for data. To load nodes asynchronously, this uses an additional plugin which overrides toggle(), making it use $.ajax to request new node data.

Does it make sense to use Backbone with this plugin, and how would you go about doing so? I assume it would involve writing an alternative 'async' plugin which uses Backbone directly?

Here is what I have so far:

;(function($) {

var proxied = $.fn.treeview;
$.fn.treeview = function(settings) {
    // if (!settings.url) {
        // return proxied.apply(this, arguments);
    // }
    var container = this;

    var TreeNodeCollection = Backbone.Collection.extend({
        url: '/api/subfolder_list',
        tagName: 'ul',

        initialize: function() {
        },

        parse: function(response) {
            container.empty();
            $.each(response, this.createNode, [container]);
        //$(container).treeview({add: container});
        },

      createNode: function(parent) {
            var current = $("<li/>").attr("id", this.id || "").html("<span>" + this.text + "</span>").appendTo(parent);
            if (this.classes) {
                current.children("span").addClass(this.classes);
            }
            if (this.expanded) {
                current.addClass("open");
            }
            if (this.hasChildren || this.children && this.children.length) {
                var branch = $("<ul/>").appendTo(current);
                if (this.hasChildren) {
                    current.addClass("hasChildren");
                    if (typeof branch.collection == 'undefined') {
                      branch.collection = new TreeNodeCollection();
                    }
                    branch.collection.createNode.call({
                        classes: "placeholder",
                        text: "&nbsp;",
                        children:[]
                    }, branch);
                }
                if (this.children && this.children.length) {
                    if (typeof branch.collection == 'undefined') {
                      branch.collection = new TreeNodeCollection();
                     }
                    $.each(this.children, parent.collection.createNode, [branch])
                }
            }

            $(parent).treeview({add: container});
        }
    });

    container.collection = new TreeNodeCollection();

    if (!container.children().size()) {
        container.collection.fetch();
    }
    var userToggle = settings.toggle;
    return proxied.call(this, $.extend({}, settings, {
        collapsed: true,
        toggle: function() {
            var $this = $(this);

            if ($this.hasClass("hasChildren")) {
                var childList = $this.removeClass("hasChildren").find("ul");
                //load(settings, this.id, childList, container);
                container.collection.fetch();
            }
            if (userToggle) {
                userToggle.apply(this, arguments);
            }
        }
    }));
};

})(jQuery);
Chad Johnson
  • 21,215
  • 34
  • 109
  • 207
  • What's stopping you from calling `$.ajax` directly in your code? Backbone.sync is nothing special... – PhD May 17 '12 at 19:41
  • It is incompatible with something Qt/Webkit-related. I COULD override $.ajax similarly to how Backbone.sync() is overridden... – Chad Johnson May 17 '12 at 20:26
  • `Backbone.sync` should be fine, here, but @JayC raises some good points in his answer. You might also check out backbone-relational (https://github.com/PaulUithol/Backbone-relational) to help maintain your hierarchy. – rjz May 17 '12 at 20:48

1 Answers1

0

I realize you're probably doing this as an exercise to get into Backbone, which is not a bad thing, but I do feel you need some tips.

  1. typically collections do not have anything to do with the DOM. The parse method is there in case the default method of parsing, flattening, and/or zeroing in on your data you want to model.
  2. To handle the manipulation and the event delegation related the DOM, you'd use Backbone View (literally a new instance created from a Backbone.View extension, but I think you already get that idea).

In your case, things are likely tricky because you're likely dealing with hierarchical (mult-level) JSON data, which Backbone doesn't deal with out of the box. (Nor, arguably, does it need to, although it might be nice if some conventions were developed to deal with such things.**) This question deals with that some. I think Derick Bailey (who answered that question) actually may have written a Backbone module to deal with such things, but I haven't investigated it (any of his solutions or that problem in particular) myself. This may be reference to one particular solution.

** That isn't to say that there isn't any conventions already out there, I just don't personally know of any.

Community
  • 1
  • 1
JayC
  • 7,053
  • 2
  • 25
  • 41