Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

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

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

like image 597
a paid nerd Avatar asked Feb 16 '11 07:02

a paid nerd


People also ask

What are views in Backbone JS?

The Backbone. js Views specify how your data looks like. They represent model's data to the users. They can be used with any JavaScript template library.

How can we get the attribute value of a model in Backbone JS?

js Get model is used to get the value of an attribute on a model. Syntax: model. get(attribute)

What is the use of set element in the view?

js setElement method is used to apply backbone view to a different DOM element. It also creates a cached $el reference and displaces the view's delegated events from the old element to the new one.

What is backbone JS give its features?

Backbone. js allows developers to develop one page applications and front-end much easier and better using JavaScript functions. Backbone provides different types of building blocks like models, views, events, routers and collections for assembling client side web applications.


2 Answers

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); 
like image 178
Ed . Avatar answered Sep 24 '22 14:09

Ed .


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.

like image 31
Bill Eisenhauer Avatar answered Sep 23 '22 14:09

Bill Eisenhauer