Monday, June 3, 2024
 Popular · Latest · Hot · Upcoming
17
rated 0 times [  24] [ 7]  / answers: 1 / hits: 16368  / 14 Years ago, wed, february 16, 2011, 12:00:00

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 — what would be the best way to get the view for the element?



For example, say some event affects a bunch of elements on a page and I want to call a method on every view associated with the affected elements.



One way would be to assign the view to the element's data, but I'm wondering if I've missed something smarter:



var myview = BackBone.View.extend({
initialize: function(options) {
$(this.el).data('view', this);
...
}
});


(I'm using Backbone with jQuery 1.5.)


More From » jquery

 Answers
71

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);

[#93720] Monday, February 14, 2011, 14 Years  [reply] [flag answer]
Only authorized users can answer the question. Please sign in first, or register a free account.
kaia

Total Points: 574
Total Questions: 109
Total Answers: 110

Location: Malaysia
Member since Wed, May 11, 2022
2 Years ago
;