Check if 'this' is $(this) or just plain old 'this' - javascript

I have one function:
function myFunction(){
var id = $(this).attr('id');
}
Now sometimes, myFunction gets called with $(this) as the context but sometimes the context is just 'this'.
In one line how can I do something similar to this:
if(this == $(this)){
var e = $(this);
}
Basically a test to see if 'this' is a jQuery 'this' or a JS 'this'.
Possible?

if (this.jquery) { // refers to jQuery version
// jQuery object
}
Alternatively:
if (this instanceof jQuery) { // prototype chain
// jQuery object
}
However, as others have said, it doesn't really matter, $(this) will work whether or not this is already a jQuery object or a DOM element.

You can also just do var e = $(this) when this is a jQuery object or if it's not.

One way to deal with it would just be to always wrap it in $(...). Wrapping a jQuery object like that creates a clone (see the jQuery docs), so this HTML:
Test Link​​​​​​​​​​​​​​​​​​​​​​​
with this JS:
​var link = $('#test-link');
var doubleWrappedLink = $(link);
alert(doubleWrappedLink.attr('href'));​​​​​​​
will correctly pop up "test".

You can use the following snippet:
if (obj instanceof jQuery || 'jquery' in Object(obj)) { }
Take a look at: Check if object is a jQuery object

Related

jQuery objects and elements

I know I've seen a beautifully straightforward answer to a similar question before, but I haven't been able to remember or locate it, so apologies in advance.
I'm not new to coding, but I've had no formal training with Javascript/jQuery. Everything else I used has been strictly typed, so I'm still struggling with how JS does typing. I have a function that fires every time a child of a specific class is changed (I'm writing this for Sharepoint, so there is some working-around that has to be done.)
Why is it when I write this:
$(".listen *").change(function(event) {
var element = event.target;
if (element.title == 'Workstation')) {
alert(element.val());
}
}
I get an error that .val() is not a function, and I have to instead write
$(".listen *").change(function(event) {
var element = event.target;
if (element.title == 'Workstation')) {
alert($('#' + element.id).val());
}
}
What is the difference between the object that "element" is and the object retrieved by using the id? Aren't they both jQuery objects? I realize that not all objects returned by my function might actually have a value to return, but I don't understand how the distinction is being made.
Thanks!
In your first code block the 'element' variable is not a jQuery object, it is a DOM object. The .val() method is not defined for DOM objects. It is only defined for jQuery objects.
In your second code block $('#' .element.id) returns a jQuery object that does have the val() method defined.
So to answer your question, No they are not both jQuery objects, only the second one is.
You must make jQuery object from your dom (event.target) like that;
$(".listen *").change(function(event) {
var element = $(event.target);
if (element.attr('title') == 'Workstation')) {
alert(element.val());
}
}
Then you can use your jQuery object as you want. By the way, if you want to catch the changed element, you can use $(this) instead of $(event.target).
$(".listen *").change(function(event) {
var element = $(this);
if (element.attr('title') == 'Workstation')) {
alert(element.val());
}
}

about javascript / jquery syntax

I couldn't find the syntax something like this anywhere:
var mz = jQuery.noConflict();
mz('#zoom01, .cloud-zoom-gallery').CloudZoom();
This means: jQuery.noConflict()('#zoom01, .cloud-zoom-gallery').CloudZoom();
And something like this:
$(window)[this.off?'off':'on']("scroll", fixDiv );
So, I'm wondering about the syntax something like of these:
jQuery.noConflict()(syntax) and $(window)[syntax](syntax) and I also think there might be something like this $(selector){syntax}
Can anyone elaborate of those syntax?
The best place to start is the documentation
$.noConflict()
Many JavaScript libraries use $ as a function or variable name, just
as jQuery does. In jQuery's case, $ is just an alias for jQuery, so
all functionality is available without using $. If you need to use
another JavaScript library alongside jQuery, return control of $ back
to the other library with a call to $.noConflict(). Old references of
$ are saved during jQuery initialization; noConflict() simply restores
them.
In other words, noConflict() sets a variable to equal jQuery, so this
var mz = jQuery.noConflict();
mz('#zoom01, .cloud-zoom-gallery').CloudZoom();
is the same as
$('#zoom01, .cloud-zoom-gallery').CloudZoom();
or
jQuery('#zoom01, .cloud-zoom-gallery').CloudZoom();
noConflict() does not directly take selectors, it's just a function that sets jQuery in a certain scope to a variable so you can have multiple versions of jQuery (which you shouldn't) or use other libraries that also uses $ for something, it does not mirror the selector engine or anything else, even if it might seem so at first glance, it simply returns an instance of jQuery
In javascript there is dot notation and bracket notation, so an object can be accessed as
object.propertyName
or
object['propertyName']
as everything in javascript is an object, even jQuery methods, they can be accessed as
$('#element').fadeIn(200);
or
$('#element')['fadeIn'](200);
it's the same thing, so doing
$(window)['on']("scroll", fixDiv );
is the same as
$(window).on("scroll", fixDiv );
the advantage of using brackets is that they can contain any string, even variables, or in this case ternary statements, or the returned result of a function
var event = 'on';
$(window)[event]("scroll", fixDiv );
or
var event = this.off ? 'off' : 'on';
$(window)[event]("scroll", fixDiv );
that one also uses this, which in the global scope would be window, and it's the same as
$(window)[this.off ? 'off' : 'on']("scroll", fixDiv );
The ternary statement itself is just a fancy condition, and this
var event;
if (this.off) {
event = 'off';
} else {
event = 'on';
}
is exactly the same as
var event = this.off ? 'off' : 'on';
Added for the edited question :
jQuery() or $() is a function, something we can tell from the parenthesis, so it's something like
function jQuery(arguments) {
// do something
}
which can be called as
jQuery(some_arguments);
and as var $ = jQuery one can also do $();
Now that we know it's a function, it makes sense that we can do
$('#element_id')
and internally jQuery checks what kind of argument we passed, it sees that is's a string, and it's starting with #, so it's an ID, and then jQuery can do document.getElementById() and get that DOM element, and at the same it wraps that element in a new array-like object, usually referred to as a jQuery object.
We can also pass in a DOM node, array, object or anything else, and jQuery tries to figure out what it is, and wrap in that jQuery object for us to use with other jQuery methods, so this :
$({x:10, y:20})
is the same as
var obj = {x:10, y:20};
$(obj)
and its turned into one of those jQuery objects with the properties x and y. Passing in an object like this means we can chain on methods, and those properties are available in the methods.
$({x:10, y:20}).animate({x:50}, 1000);
And that's basically how it works, simplified a lot.
As for passing objects to methods, that's a very common way to pass arguments.
To see how it works, it's easiest to create a method:
$.fn.doStuff = function(argument) {
this.css(argument);
}
inside a jQuery plugin, this is the jQuery object, and we can now use the mothod above that does nothing more than pass the arguments to jQuery's css().
We know we can pass an object to css() like this :
$('#element').css({left: '10px', top: '20px'});
so using our plugin we can do the same
var obj = {left: '10px', top: '20px'};
$('#element').doStuff(obj);
and it ends up doing exactly the same thing. Of course, we could do anything with the object :
$.fn.doStuff = function(args) {
if ( typeof args == 'string' ) {
alert(args); // if it's a string, just alert it
} else if ( typeof args == 'object' ) {
for ( var key in args ) { // if it's an object, iterate
this[0].style[key] = args[key]; // and do something
}
}
}
foo['bar'] syntax is to get the property bar from object foo.
foo() is to execute the function foo.
And you can combine these as you wish.
jQuery.noConflict() returns a function so you could execute the result by jQuery.noConflict()(syntax).
$(window) returns an object so you could get a property from it by $(window)[syntax], and if the property is a function, then you could execute it by $(window)[syntax](syntax).
This is just javascript syntax.
person.name is exactly the same as person["name"]
The same happens with methods
$(window).on(...) is exactly the same as $(window)["on"](...)
One cool thing about the second way is that you can make the member name variable, for example:
So doing:
var windowMethod = "on";
$(window)[windowMethod](...)
is the same as
$(window)["on"](...)
And you can have an expression inside the brackets, so this:
$(window)[this.off ? 'off' : 'on']("scroll", fixDiv );
would be exactly the same as doing this:
if(this.off)
$(window).off("scroll", fixDiv);
else
$(window).on("scroll", fixDiv);
But the former is shorter.
Hope this helps. Cheers
PS: The jQuery.noConflict()(syntax) is straightforward, .noConflict() just returns a function and then we append some other parens to call it just as any other function.

What is the proper way to acces a property from an object inside several scopes of a method?

For example, if I have the object:
function Website(){
this.images = [];
}
Website.prototype.getImages = function(){
jQuery('img').each(function(key, val){
this.images.push(val.src);
})
}
and I try to call website.getImages() I get this error: TypeError: Cannot call method 'push' of undefined
So, in order to fix this, I would do:
Website.prototype.getImages = function(){
var images = this.images;
jQuery('img').each(function(key, val){
images.push(val.src);
})
}
But I don't see this solution as clean, because what if im trying to access several variables.
Is there a cleaner and better way to do this?
You can do this:
Website.prototype.getImages = function(){
var self = this;
jQuery('img').each(function(key, val){
self.images.push(val.src);
// self.someOtherProperty
// self.someMethod()
})
}
In a general sense this is set according to how a function is called, so as soon as you nest functions you have to do something to ensure this is set correctly for the inner function, e.g., .call() or .apply() - or .bind(), though .bind() isn't supported by IE until version 9.
jQuery functions that take callbacks always set this to something logical - in most cases the particular DOM element being processed at the time. But of course that doesn't help when you want it to be something else.
It depends on what you call "clean". It's very readable. Another idea is using .bind which passes the this value, so that you can still use your first snippet:
jQuery('img').each(function(key, val){
this.images.push(val.src);
}.bind(this)); // set the `this` inside `.each` to the one it is currently
You are doing it right. The reason for this behavior is that jQuery will force this to be each matched <img> on the .each() callback.
No, I think not. The this keyword it known to be set to the DOM element in almost all jQuery callback functions. Something like
jQuery('img').each(function(key, val){
this.images.push(val.src);
}.bind(this));
would make it more messy than it must be. The "self" or "that" dereferencing-variable is the standard way to do this. However, you could easily do without jQuery:
var imgs = document.getElementsByTagName("img");
for (var i=0, l=imgs.length; i<l; i++)
this.images.push(imgs[i].src);
...which is a line shorter, faster than jQuery and working cross-browser as well.
Another option is to use jQuery.proxy. Its basically a wrapper for the Function.bind function that others have mentioned. Except that it works in all browsers.
Website.prototype.getImages = function(){
jQuery('img').each(
jQuery.proxy(function(key, val){
// 'this' now refers to the instance of Website
this.images.push(val.src);
this.other_property = 'awesome';
}, this)
);
}

Can't call $.data on object inside function

I'm playing around with the jQuery $.data function, and I'm running in to some trouble. If I do like this:
(function($){
$.fn.testData = function() {
var obj = $(this);
obj.text($.data(obj,'test'));
}
})(jQuery);
var element = $("#test");
$.data(element,'test','hej');
element.testData();
this comes out as undefined. Why?
EDIT:
It works just fine if I use the elem.data(key) function, like this:
(function($){
$.fn.testData = function() {
var obj = $(this);
obj.text(obj.data('test'));
}
})(jQuery);
var element = $("#test");
element.data('test','hej');
element.testData();
but I just saw an slideshow by Paul Irish, which claims that elem.data is 10x slower than $.data(elem):
http://paulirish.com/2009/perf/
(function($){
$.fn.testData = function() {
var obj = $(this);
obj.text($.data(obj[0],'test'));
}
var element = $("#test");
$.data(element[0],'test','hej');
element.testData();
})(jQuery);
Here is the jsFiddle: http://jsfiddle.net/TdJHq/
jQuery.data (doc jQuery.data) works on DOM elements, not on jQuery elements. So you must extract the real element under your jQuery selector.
obj.text($.data(obj[0],'test'));
This is what #alexl explained.
But there is also a .data() method, that works on a jQuery selector, so you could use:
// getter
obj.text($obj.data('test'));
// setter
obj.text($obj.data('test','toto'));
And you may have mixed both.
The problem is that you are creating different objects for attaching and retrieving the data. Whenever you call $(selector), you are creating a new jQuery object and this it will be different than the one you attached the data to.
Here is a simple example:
$.data($('#test'),'test','hej');
alert($.data($('#test'),'test'));
It will give you undefined.
That is why $.data expects a DOM element and not a jQuery object. No matter how you retrieve a certain DOM element, the reference is always the same.
So either pass the DOM element ($('#test')[0]) or better, use $('#test').data().

passing javascript object to function in a jquery way?

Yeah so I've been messing around with javascript a while but only recently got into stuff like object orientation, prototyping and using objects for all functions and vars.
But, many frameworks like jQuery or extJS have something I have yet to grasp, you can define an object by using a built in function for searching the dom, example:
var a = $('#mydiv');
and then you can do a.click(function);
So my question is, how can I create a "framework" of sorts where I can write code in that style, like example:
var mydiv = document.querySelector('mydiv');
mydiv.neph(args,args);
So I have my object defined, in this case it's a dom element or whatever, now I pass it to my function "neph" with arguments, I want to create code that allows me to do this. But since mydiv does not have any function, it only has in this case the dom element right so mydiv.neph does not exist, but in jquery you can define whatever var and .click or .mouseover or whatever does exists within the object as functions? Confusion ensues! :D
Ok sorry if this is a retarded question btw =P
jQuery and other libraries define a function called $ that takes several optional parameters. The object returned by calling $ is not a DOM element, but a jQuery object wrapping a DOM element up with a set of convenient functions.
You can do something similar yourself:
<html>
<body>
<input id="derp" type="text"/>
<script type="text/javascript">
function $(id)
{
return new myLibrary(id);
};
function myLibrary(id)
{
this.el = document.getElementById(id);
};
myLibrary.prototype.help = function()
{
alert(this.el.id);
return this;
};
// Woah! My own fake jquery!
$("derp").help();
</script>
</body>
</html>
jQuery is far more sophisticated, of course. For example, it will use apply and call to set this correctly in calls like jQuery.each.
You need to create a Prototype in javascript. This is what allows you to add a function to an object that's already defined (i.e. the .click() function that you gave as an example).
You can have a look at the jQuery code, it's open source. It's not the simplest code, but you can still see how it works and how they do it.
Mike's comment is a good answer: Look at jquery or Ext-Core's sources.
Maybe what you're missing is that, in jquery, for instance $() returns a jquery object, which wraps the plain vanilla DOM node, providing extended functionality.
In jQuery, $ is just an alias to the jQuery object. So when you call $('#mydiv'); you're really calling a function like jQuery('#mydiv'); So part of what makes jQuery so cool is that every the $() function returns this, which means when you call the $() you're getting a handle to the jQuery object and all of the methods it has on it. That is what allows you to do something like this:
var a = $('#mydiv');
a.click(function() { // etc etc etc });
So to pull off your example:
var mydiv = document.querySelector('mydiv');
mydiv.neph(args,args);
You'd have to create an object that has a function called neph on it and return that object in the context of mydiv when you call querySelector.
var myFramework = function() {
this.context = undefined;
this.neph = function(arg, args) {
console.log(arg, args);
}
};
var myCuteFunction = function(element) {
var f = new myFramework();
f.context = element;
return f;
}
// ...
var x = myCuteFunction('#mydiv');
x.neph(arg, args);
Since nobody has really answered about Ext, you can easily extend the element wrapper prototype:
Ext.override(Ext.Element, {
myMethod: function(a, b){
console.log(a, b, this);
}
});
"this" will refer to the Ext.Element object.

Categories