What's the difference between: $(this.el).html and this.$el.html - javascript

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.

Related

Whats the meaning of $('element',this.el)[0]?

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

jQuery / JavaScript, why do I need to wrap variables in $() to use them?

Say I have a map on an array of elements. The callback function takes the index and the value at that position in the array.
If I wrap the array element that the callback receives in $(), it behaves as I expect. If I use it without wrapping it in $(), it gives an error.
var nonHiddenElements = $( "form :input" ).not(':hidden');
nonHiddenElements.map(function(index, element){
input_id = $(element).attr('id'); // this works
input_id = element.attr('id') ; // this gives an error
})
Can someone explain how this works.
Is this a jQuery quirk, or a JavScript thing?
What type of objects does my nonHiddenElements array contain exactly?
What is element that gets passed to the callback?
And mainly what is the $() doing?
You need to understand how jQuery actually works. I will try to explain it briefly.
$ is nothing but a normal javascript function. jQuery === $, is just a function with a fancy name. This function does a lot of different things, depending on what you pass in it. For example if you pass a string it will be treated as CSS selector and jQuery internals will try to find corresponding DOM elements. Or if you pass a string starting with < and ending with > jQuery will create a new DOM element by provided HTML string.
Now if you pass a DOM element or NodeCollection of DOM elements, it/they will be wrapped into jQuery instances so that they can have a jQuery prototype methods. There are many prototype methods jQuery offers. For example text, css, append, attr - those are all methods of jQuery prototype. They are defined basically like this (simplified):
jQuery.prototype.text = function() { ... }
Normal DOM elements don't have those convenient methods jQuery provides. And inside of methods like map or each if you check this value or element parameter like you do, you will see that they are actually not jQuery instances:
element instanceof jQuery // => false
and of course you can't use instance methods with not an instance.
So in order to use jQuery prototype methods you need have a jQuery instance, which you can obtain if you call jQuery function with DOM element passed in it:
$(element) instanceof jQuery // true
Javascript is a programming language.
jQuery is a JavaScript Library.
With jQuery:
$("some element")
In native JavaScript you would have to do something like this.
getElementById('elementByID')
Explained in detail here: https://developer.mozilla.org/en-US/docs/Web/API/document.getElementById
MDN is a great resource for beginners. https://developer.mozilla.org/en-US/docs/Web/JavaScript

Most efficient way to re-use jQuery-selected elements

I can imagine the correct answer to this based on theory, but I'm just looking for some confirmation. I'm wondering what the most efficient way to re-use a jQuery-selected element is. For example:
$('#my_div').css('background','red');
//some other code
$('#my_div').attr('name','Red Div');
vs.
myDiv = $('#my_div');
myDiv.css('background','red');
//some other code
myDiv.attr('name','Red Div');
I assume the second example is more efficient because the element #my_div doesn't have to get found more than once. Is that correct?
Similarly, is it more efficient to first save $(this) in a varaible, such as 'obj', and then reuse 'obj' rather than using $(this) over and over? In this case, jQuery isn't being forced to find an element over and over again, but it IS being forced to convert this to a jQuery object [$(this)]. So as a general rule of thumb, should a jQuery object ALWAYS be stored in a variable if it will be used more than once?
You should write your code such that you limit the number of DOM traversals.
When you write something like this:
$('#my_div').css('background','red');
//some other code
$('#my_div').attr('name','Red Div');
You are finding #my_div twice, which is inefficient.
You can improve this either by assigning the result of a selector (i.e. var x = $('.something')) and manipulate the variable x, or you can chain your method calls like this:
$('#my_div').css('background','red').attr('name','Red Div');
You'll see the above code used a lot, because you're finding the element once. The css() method will apply a CSS style and return the actual result of $('#my_div'), so you can invoke another method, in this case attr().
My preferred way of handling the re-use of selectors is to store them as a variable, and wrap my stuff in a closure.
if you're using jQuery selector (like $('#element')), then yes, you should always store your results.
if you're using object and wrapping it in jQuery (like $(this)), it's not necessary, because jQuery doesn't need to search for that element again.
One thing that I find is generally overlooked is just how powerful jQuery chains are. It may not be so noticeable, but since jQuery caches your wrapped elements within a chain, you can modify elements, go into a more specific subset, modify, then go back up into a a general superset without much overhead.
I expect something like (pardon the example)
$('#myDiv')
.addClass('processing')
.find('#myInput')
.hide('slow')
.end()
.removeClass('processing')
;
to be better performance-wise than even
var $myDiv = $('#myDiv').addClass('processing');
var $myInput = $('#myDiv #myInput').hide('slow');
$myDiv.removeClass('processing');
This also holds for applying the jQuery function to elements returned in an event handler. Try to avoid applying $(...) too many times, because this is slow. Instead create a variable that contains the result of $(...). Good practice is to start the variable with a $, which gives a hint about the jQuery object inside the variable.
$('a').click(function(){
var $this = $(this);
$this.addClass("clicked");
$this.attr("clicked", true);
});

Wrapping a DOM element inside a JavaScript object

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.

Why do I have to use $(this)? [duplicate]

This question already has answers here:
Closed 12 years ago.
Possible Duplicate:
jQuery $(this) vs this
In jquery sometimes I find that within a function I have to use $(this) because this won't work:
var listItems = $('li');
listItems.each(function(index) {
$(this).css({
})
})
Any ideas as to the reason why?
$() is the jQuery constructor function
this is a reference to the DOM element of invocation
So basically, you're turning a DOM reference into a jQuery object
In your example, you could also use
listItems.each(function(index, element){
$(element).css({
});
});
..since .each() will pass both, index + element in its callback.
I know I'm a bit late to this thread but I just wanted to bring up the fact that redundant wrapping of DOM objects is one of the most frequently committed crimes against jQuery. Taking care with your jQuery-instance constructing can have tremendous effects performance-wise and it's so easy to do that you have no excuse not to.
Typically, when people have a DOM object (whether it be referenced as this or element) they'll try to wrap it each time they need access to a jQuery method:
jQuery(this).css('a', 'b');
The problem is when you're doing this multiple times:
jQuery(this).css('a', 'b');
jQuery(this).find('span').attr(...);
jQuery(this)....
Every time jQuery() is called, a new jQuery instance is constructed. That kind of operation is expensive and should be avoided if at all possible -- especially in loops!
To avoid this, for one, you could utilise chaining with all methods that return a jQuery instance $(this).css(a,b).attr(a,b)...). The rest of the time you should have a locally declared variable that refers to the jQuery instance and then just use that:
var self = jQuery(this);
self.css(...);
self.attr(...);
If you're doing this within an .each() callback function, there is still a new jQuery object being constructed on every single iteration. You can avoid this by having one generic jQuery object which you continually mutate and then you can run jQuery methods off that single instance:
Look at this:
jQuery.single = function(a){
return function(b){
a[0] = b;
return a
}
}(jQuery([1]));
Now look at this:
$('a').each(function(i){
$.single(this).append('Anchor number ' + i);
});
Only one jQuery object is being used. You can make it even faster by avoiding the identifier resolution:
$_ = $.single;
$('a').each(function(i){
$_(this).append('Anchor number ' + i);
});
Food for thought. More info here: http://james.padolsey.com/javascript/76-bytes-for-faster-jquery/
this is the native DOM element. $(this) is a jQuery object that allows you to call functions such as .css() on it.
this is typically a DOM object by default, which means it only has the methods on normal DOM objects.
If you want to invoke a library-specific function (such as jQuery's .css function), you have to convert it to a full jQuery object first, which is what $() does by default if you pass it a DOM object.
(You can also pass other things to $(), such as an HTML string (to construct a new jQuery-wrapped DOM object) or a CSS selector (to get a set of jQuery objects that correspond to DOM objects matching the selector).
If you are using Firefox, try console.log($(this)) and console.log(this) to see the difference.

Categories