Backbone.js - Given an element, how do I get the view?

后端 未结 5 1799
刺人心
刺人心 2020-12-15 03:33

I\'ve created a bunch of Backbone.js views. Each view has an associated element (view.el).

Given an element on the page — out of context of the view — w

相关标签:
5条回答
  • 2020-12-15 03:57

    You could maintain a views hash (dictionary) that uses the element as the key and returns the view (or views).

    http://www.timdown.co.uk/jshashtable/

    0 讨论(0)
  • 2020-12-15 04:08

    Since every view has a reference to the model its displaying, what I would do is assign id of the model to the view's associated element(hopefuly that is not affected by the changes by outside event). Also make sure that the model has a reference to its view. Then have these models stored in a Backbone collection.

    With this setup, once something happens to an element, you use the elements id to retrieve corresponding model from Backbone collection that you created above and then this model will give you your view reference.

    0 讨论(0)
  • 2020-12-15 04:13

    Every view can register for DOM events. As such, every view with the kind of element that you are interested in should register for the DOM event and then assign an event-responding function that does what you want. If you need to DRY things up, use mixin techniques to mix in the function.

    I think maybe this solution is easier than you may have initially imagined. Just let the views do the work that they are intended to do.

    0 讨论(0)
  • 2020-12-15 04:15

    I've just written a jQuery plugin for this. It also uses the .data() method.

    Registration:

    I have wrapped / proxied the Backbone View setElement method to attach the required data to the view's $el property.

    Registration is done behind the scenes like so:

    $(myViewsEl).backboneView(myView);
    

    Retrieval:

    The plugin traverses up the DOM hierarchy (using .closest()) until it finds an element with the required data entry, i.e a DOM element with an associated view:

    var nearestView = $(e.target).backboneView();
    

    In addition, we can specify what type of Backbone View we wish to obtain, continuing up the hierarchy until we find an instance of matching type:

    var nearestButtonView = $(e.target).backboneView(ButtonView);
    

    JSFiddle Example:

    Can be found here.

    Notes:

    I hope I am correct in thinking there are no memory leaks involved here; An 'unlink' is performed if setElement is called a second time round, and since removing a view's element calls .remove() by default, which destroys all data as well. Let me know if you think differently.

    The plugin code:

    (function($) {
    
        // Proxy the original Backbone.View setElement method:
        // See: http://backbonejs.org/#View-setElement
    
        var backboneSetElementOriginal = Backbone.View.prototype.setElement;
    
        Backbone.View.prototype.setElement = function(element) {
            if (this.el != element) {
                $(this.el).backboneView('unlink');                    
            }
    
            $(element).backboneView(this);    
    
            return backboneSetElementOriginal.apply(this, arguments);
        };
    
        // Create a custom selector to search for the presence of a 'backboneView' data entry:
        // This avoids a dependency on a data selector plugin...
    
        $.expr[':'].backboneView = function(element, intStackIndex, arrProperties, arrNodeStack) {
            return $(element).data('backboneView') !== undefined;        
        };
    
        // Plugin internal functions:
    
        var registerViewToElement = function($el, view) {
            $el.data('backboneView', view);
        };
    
        var getClosestViewFromElement = function($el, viewType) {
            var ret = null;
    
            viewType = viewType || Backbone.View;
    
            while ($el.length) {
                $el = $el.closest(':backboneView');
                ret = $el.length ? $el.data('backboneView') : null;
    
                if (ret instanceof viewType) {
                    break;
                }
                else {
                    $el = $el.parent();
                }           
            }
    
            return ret;                
        };
    
        // Extra methods:
    
        var methods = {
    
            unlink: function($el) {
                $el.removeData('backboneView');        
            }
    
        };
    
        // Plugin:
    
        $.fn.backboneView = function() {
            var ret = this;
            var args = Array.prototype.slice.call(arguments, 0);
    
            if ($.isFunction(methods[args[0]])) {
                methods[args[0]](this);                        
            }
            else if (args[0] && args[0] instanceof Backbone.View) {
                registerViewToElement(this.first(), args[0]);                
            }
            else {
                ret = getClosestViewFromElement(this.first(), args[0]);
            }
    
            return ret;        
        }        
    
    })(jQuery);
    
    0 讨论(0)
  • 2020-12-15 04:24

    I've been using a method inspired by Ed's solution but it does not require the use of jQuery. It does two things:

    1. It sets the attribute data-backbone-view on the root elements of all views. This is convenient when looking at the DOM tree in a debugger. You can immediately see which elements are associated with views. You can also use the CSS selector [data-backbone-view] to find elements that are the roots of Backbone views.

    2. It adds a backboneView property to each root element of a view. It is then possible to get from the DOM element to the view by looking a the DOM element's properties.

    I turn this on only when I'm debugging. Here is the code:

    var originalSetElement = Bb.View.prototype.setElement;
    
    Bb.View.prototype.setElement = function setElement(element) {
      if (this.el && this.el !== element) {
        delete this.el.backboneView;
      }
    
      element.backboneView = this;
      element.setAttribute("data-backbone-view", "true");
    
      return originalSetElement.apply(this, arguments);
    };
    
    0 讨论(0)
提交回复
热议问题