I see this in someone's code: this.$('.selector') and am curious what that does. "this" is a Backbone view. So what does prefixing "this." onto a jQuery selector, in the given context, do?
From the doc:
$ (jQuery or Zepto)view.$(selector)
If jQuery or Zepto is included on
the page, each view has a $ function that runs queries scoped within
the view's element. If you use this scoped jQuery function, you don't
have to use model ids as part of your query to pull out specific
elements in a list, and can rely much more on HTML class attributes.
It's equivalent to running: view.$el.find(selector)
ui.Chapter = Backbone.View.extend({
serialize : function() {
return {
title: this.$(".title").text(),
start: this.$(".start-page").text(),
end: this.$(".end-page").text()
};
}
});
In short, it's used to access some elements of View with a familiar syntax.
It is basically limiting the search for elements with a class of selector to the element your View is based off of.
It's basically changing the scope of the search from document to this, which is obviously some element.
Related
Now I learning Backbone and Marionette, I read some tutorial and I found a code whom I haven't understand. Here's the code:
$('element',this.el)[0]
I know jQuery little bit. I know this keyword, i know the $('element') keyword, but not understand that code, please everybody tell me about that.
This $('element',this.el) says select all <element> contained within this.el. this.el must be another "object" but what it is depends on what is building this higher up. I cover this in more detail in this answer to a similar question.
The [0] simply unwraps the jquery object returning a vanilla DOM object. So:
$('element',this.el).first(); //works
$('element',this.el)[0].first(); //will error
The second errors becuase it is no longer a jquery object so it is not wrapped in the jquery functions.
In Backbone context, your code is probably found inside a view and this.el refers to the view's element
$('element',this.el) find the element nodes inside the scope defined by this.el
$('element',this.el)[0] refers to the first element node found
Note that in a Backbone view, you can simplify to
this.$('element')[0]
This is the jquery selector context syntax:
'element' is to a selector and this.el is a context and using bracket notation to get the first element [0] which also converts jquery element to javascript object.
Alternatively you can use like this instead of jquery selector context syntax:
$(this.el).find('element')[0] // hope you understand this syntax
So I have a set of jQuery plugins, really basic stuff, but I split the code into plugins because I don't like having a huge jQuery(document).ready() function where I store the entire application logic.
Each plugin has a "destructor", which is basically a function that I defined in the plugin prototype object. This function unbinds events used by the plugin, removes DOM elements that were added by the plugin etc.
Plugins are initialized like this:
$('.element').plugin();
Is there any way I can get all the elements that have my plugins attached to them, from another plugin which is supposed to replace the body HTML, so I can call the destructor function?
I was thinking to store each plugin instance inside a global array, then I can access that array from any plugin. But maybe there is a better way that doesn't use the global state?
I don't think there is a ready made method for it... but as a hack you can add a class to the target elements in your plugin and then use that class to get all elements with the widget initialized lke
$.fn.plugin = function(){
this.addClass('my-plugin-class');
}
then to initialize
$(element).plugin()
to get all elements with the plugin
$('.my-plugin-class')....
But if it is a jQuery UI widget then you can use the selector $(':ui-widgetname'), see this answer
Arun P Johny wrote the rigth idea -- just delete 'footprint' of your job by marking the affected DOM elements with some specific class name.
I want just add an idea. Plugins are the methods of the library and nothing more. If you need the destroyer for constructor -- just make another plugin for it:
$.fn.overture = function (){...};// construct
$.fn.crescendo = function (){...};// more construct
$.fn.quietFarewell = function (){...};// destructor for everything above
$(...).overture().crescendo().quietFarewell();
What's the difference between:
$(this.el).html
and
this.$el.html
Reading a few backbone examples and some do it one way and other another way.
$(this.el) wraps an element with jQuery (or Zepto). So, if your view HTML was this:
<div id="myViewElement"></div>
...and this.el referenced that div, then $(this.el) would be the equivalent of retrieving it directly via jQuery: $('#myViewElement').
this.$el is a cached reference to the jQuery (or Zepto) object, so a copy of what you would get from calling $(this.el). The intent is to save you the need to call $(this.el), which may have some overhead and therefor performance concerns.
Please note: the two are NOT equivalent. this.el alone is a reference to a host object HTMLElement -- no libraries involved. This is the return of document.getElementById. $(this.el) creates a new instance of the jQuery/Zepto object. this.$el references a single instance of the former object. It is not "wrong" to use any of them, as long as you understand the costs of multiple calls to $(this.el).
In code:
this.ele = document.getElementById('myViewElement');
this.$ele = $('#myViewElement');
$('#myViewElement') == $(this.ele);
Also, it is worth mentioning that jQuery and Zepto have partial internal caches, so extra calls to $(this.el) might end up returning a cached result anyway, and that's why I say "may have performance concerns". It also may not.
Documentation
view.$el - http://backbonejs.org/#View-$el
$ in backbone - http://backbonejs.org/#View-dollar
jQuery base object - http://api.jquery.com/jQuery/
Zepto base object - http://zeptojs.com/#$()
The two are essentially* equivalent, with $el being a cached version of the jQuery or Zepto objects el, the reason why you see examples using $(this.el) is because it was only added in a later release of backbone.js (0.9.0).
*Technically as Chris Baker points out $(this.el) will (probably) create a new jQuery/Zepto object each time you call it while this.$el will reference the same one each time.
If $el exists on this and is a jQuery object, you shouldn't use $(this.el) because it would be initializing a new jQuery object when one already exists.
They yield exactly the same thing; that is, a reference to a view's element. $el is simply a jquery wrapper for $(this.el). Look at this reference: http://documentcloud.github.com/backbone/#View-$el
I usually see this:
var markup = $(this).html();
$(this).html('<strong>whoo hoo</strong>');
I agree with Raminon. Your examples you've seen look wrong.
This code is typically seen within a jquery loop, such as each(), or an event handler. Inside the loop, the 'el' variable will point to the pure element, not a jQuery object. The same holds true for 'this' inside an event handler.
When you see the following: $(el) or $(this), the author is getting a jQuery reference to the dom object.
Here's an example I just used to convert numbers to roman numerials:
(Note, I always use jQuery instead of $ -- too many collisions with mootools...)
jQuery(document).ready(function(){
jQuery('.rom_num').each(function(idx,el){
var span = jQuery(el);
span.html(toRoman(span.text()));
});
});
Wrapping an element in $() appends the jQuery extensions to the object prototype. Once that's done it doesn't need to be done again, although there's no harm other than performance in doing it multiple times.
I need to have two select menus in a CKEditor dialog, with the second select menu changing its options according to the selected option of the first menu. Simple enough you would think! But in CKEditor it seems really difficult to obtain the DOM equivalent of the CKEditor object. I can access the CKEditor Object but not its DOM equivalent(s).
The instance of the CKEditor select (UIElement) object has some useful DOM interactions i.e. getElement() but I can only access this object with the special this keyword within an event method within a CKEditor select "class" definition.
How can I access the instance of the CKEditor UIElement object (in this case the select)? I only have the id of the CKEditor object, CKEditor for some frustrating reason decides to apply random ids to its DOM object equivalents.
The instance object I am trying to access is documented here: (No mention of how to obtain this instance though!)
http://docs.cksource.com/ckeditor_api/symbols/CKEDITOR.ui.dialog.select.html
In fact the CKEDITOR.dialog.getCurrent() method will allow you to access the Dialog instance from any function, and from there you can access the UIElement instance of any CKEditor object you're after.
Can you cache what you need in the setup callbacks during your dialog's initialization?
You can pass the setup functions an object and they could put what they need in there. So you'd pass an object into your setup stuff:
onShow: function() {
//...
this.cachedDomIds = { };
this.setupContent(this.cachedDomIds);
//...
}
And then in your setup:
setup: function(cache) {
//...
cache.some_dom_id = this.domId;
//...
}
Then at least you'd have access to all the real DOM id attributes and you could getElementById() as needed.
Thanks for the suggestion mu is too short,
I found I could access the other select menus by using this method:
this.getDialog().getContentElement([insert_dialog_name_here], this.getValue()).getElement()
this.getValue will have the same id of the CKEditor UI element I'm after
I've noticed a common pattern in the JavaScript I've been writing and was wondering if there is already a pattern out there that defines something similar as best practice? Essentially, it's how to get a DOM element and wrap it inside / associate it with a JavaScript object. Take this example, where you need a filter in your web app. Your page looks like this:
<html>
<head></head>
<body>
<div id="filter"></div>
</body>
</html>
You'd then wrap the element like so:
var myFilter = new Filter({
elem: document.getElementById('filter'),
prop: 'stacks-test',
someCallback: function() {
// specify a callback
}
});
And the JavaScript (where spec is an object passed to the constructor):
var Filter = function(spec) {
this.elem = spec.elem;
this.prop = spec.prop;
this.callback = spec.someCallback;
this.bindEvents();
};
Filter.prototype.bindEvents = function() {
var self = this;
$(this.elem).click(function(e) {
self.updateFeed();
};
};
Filter.prototype.updateFeed = function() {
this.prop; // 'stacks-test'
this.callback();
// ...
// code to interact with other JavaScript objects
// who in turn, update the document
};
What is this kind of approach called, and what are the best practices and caveats?
You might be interested in Dojo's widget library, Dijit - if I'm understanding your question correctly, it essentially does what you're asking, and a whole lot more.
In Dijit, a widget essentially encapsulates a DOM node, its contents, any JavaScript that defines its behavior, and (imported separately) CSS to style its appearance.
Widgets have their own lifecycle, registry, and events (including many which simply map to DOM events on a node within the widget, e.g. myWidget.onClick could effectively call myWidget.domNode.onclick).
Widgets can (but don't have to) have their initial contents defined in a separate HTML template file, through which it's also possible to bind events on nodes within the template to widget methods, as well as set properties on the widget that reference particular nodes in the template.
I'm barely scratching the surface here. If you want to read more on this, you can start with these reference pages:
http://dojotoolkit.org/reference-guide/dijit/info.html
http://dojotoolkit.org/reference-guide/dijit/_Widget.html (the base that all widgets extend)
http://dojotoolkit.org/reference-guide/dijit/_Templated.html (RE the HTML templating)
http://dojotoolkit.org/reference-guide/quickstart/writingWidgets.html (useful information when starting to write your own widgets)
http://dojotoolkit.org/reference-guide/dijit/ (for a bunch more info)
All said, I don't know what you're ultimately aiming for, and maybe this is all a bit much for your purposes (considering I'm throwing an entire other library at you), but figured it might pique your interest at least.
Continuing from my comment on the question, jQuery is a potential tool for the job, as it already provides some of the foundations for what you're after. However, having said that, it does introduce complexities of its own, and further, not all "jQuery ways" are equal. I'll suggest one way of using jQuery as your "object model", but it may or may not suit your needs.
First things first. The philosophy of jQuery is that you start everything by selecting the element first, using $(), or equivalently jQuery(). All operations conceptually begin with this. This is a slightly different way of thinking compared to creating an object that wraps an element and keeping a reference to that wrapper, but essentially this is what jQuery does for you. A call to $('#some-id') grabs the element with id of "some-id" and wraps it in a jQuery object.
One way: Write "Filter" plugins.
Replace your constructor with a initFilter() jQuery method. You can do this by modifying the jQuery prototype and using the jQuery object as your wrapper. jQuery's prototype is referenced by jQuery.fn, so:
jQuery.fn.initFilter = function (prop, callback) {
// Save prop and callback
this.data('filter-prop', prop);
this.data('filter-callback', callback);
// Bind events (makes sense to do this during init)
this.click(function () {
$(this).updateFeed();
});
};
Then do a similar thing for updateFeed():
jQuery.fn.updateFeed = function () {
this.data('filter-prop');
this.data('filter-callback')();
});
And use it like this:
$('#filter').initFilter(prop, callback);
Note that updateFeed can simply be in-lined into the click handler to prevent unnecessary pollution of the jQuery namespace. However, one advantage of using jQuery like this is that you do not need to keep a reference to the object if you need to invoke some function on it later, since jQuery ties all references to actual elements. If you'd like to call updateFeed programmatically, then:
$('#filter').updateFeed();
will then be invoked on the correct object.
Some things to consider
There are certainly downsides to this method. One is that all properties, which we've saved against the element using .data(), are shared between all jQuery functions that act on that element. I've attempted to alleviate this by prefixing the property names with "filter-", but depending on the complexity of your object(s), this may not be suitable.
Further, this exact method may not be so suitable for objects that require a lot of manipulation (i.e. objects with many functions) since all of these functions become common to all jQuery objects. There are ways to encapsulate all this which I won't go into here, but jQuery-ui does this with their widgets, and I'm experimenting with yet another alternative in a library I'm creating.
However, pulling back a bit, the only reason I suggested using jQuery in the first place is that your Filter object appears to be heavily tied to the DOM. It binds events to the DOM, it modifies the DOM based on user interaction, basically it appears to live in the DOM, so use something DOM-based, i.e. jQuery.