Can't call $.data on object inside function - javascript

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

Related

Select ALL elements with specific data attribute Javascript?

With jquery, I've got the following code:
$('a[data-hello]').click(function(){ = That select all "a" elements with "data-hello".
I'm trying to make this with raw Javascript. I stop here:
document.querySelectorAll("data-hello").onclick = function() {
(btw, theres a way to select all the A elements with data-hello and not all with data-hello? o.O)
But querySelectorAll returns a Array. Because of this, it only works if I determine a position. This way:
document.querySelectorAll("data-hello")[5].onclick = function() {
But I want ALL ELEMENTS, not specific elements, like with jQuery. I cant use jQuery.
It is so simple with Jquery :( I must make a "for" to wade through all the positions in JS? Is this necessary? sorry I do not understand...
What I want to do:
I want to get the data attribute value of the element that is clicked. I use this for this inside the function and, then, I applied another function that add a class in a specific element.
Basically, there is buttons with classes in data attribute value. This classes will be applied to a specific element.
Put the array (actually a NodeList) of elements in a variable and loop through them to set the event handler on each of them. That's what the jQuery methods do to apply something to all elements in a jQuery object. There is no way around the loop, with jQuery it's just hidden within the methods. You can use the same selector syntax as in jQuery with querySelectorAll.
var arr = document.querySelectorAll("a[data-hello]");
var f = function() {
// do something
};
for (var i = 0; i < arr.length; i++) {
arr[i].onclick = f;
}
querySelectorAll accepts a string of comma-separated CSS selectors, just like jQuery, so you can give it the same string: 'a[data-hello]'.
The difference between native and jQuery that you are running into is in calling methods on the elements returned. jQuery returns a jQuery object, which has methods that often loop over all the elements, .click() being one such methods. You need to replicate that with the array of elements that querySelectorAll is returning by looping over the array and applying the same handler to each element's onclick property.
Try this:
var myElements = document.querySelectorAll("a[data-hello]");
Array.prototype.forEach.call(myElements, function (element) {
element.onclick = function () {
// Your onclick handler code goes here.
console.log('clicked', element);
};
});
as simple as that:
var dataElems = document.querySelectorAll("[data-hello]")
for (var i=0;i<dataElems.length;i++) {
dataElems[i].onclick = function(i,v) {
alert(this.innerHTML)
}
}
example http://jsfiddle.net/acrashik/W86k8/

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

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

is there a way to return a selector to an element? is it $(this) or some other method?

I get a lot of stuff moving about, and i was going to make a hashmap in javascript to allow me to remember certain things, one of which is objects recently touched. With that said, i was curious if i could create a key->value or array which hold the selector of the item clicked.
I wasnt sure if it was something like:
var item = new Array();
$("div.item").click(function(){
item.push($(this));
});
Then each item that is clicked is added to the array and i could do something like:
$(item).each(function(){
$(this).css("background-color","red");
});
Instead of using an array, you can use a jQuery object:
var $items = $();
$("div.item").click(function () {
$items = $items.add(this);
});
$items.css('background-color', 'red');
http://jsfiddle.net/b5qaT/
Make an empty jQuery collection and add to it.
var items = $([]);
$("div.item").click(function(){
var elem = $(this);
items = items.add(elem);
});
You want to pass the event as an argument in your eventhandler function. Like so:
$("div.item").click(function(e){...
e.whateverYouWantToDoWithIt;
The event is a javascript object, not jquery. You can google javascript event methods, attributes, etc. to see what you can do with it.
EDIT
Sorry, I read your question kind of fast. If you want to store the actual DOM object (the div) in the array, then yes, you would use the $(this) selector.

why is jQuery selector property undefined within each()?

Given the following code, why does the selector property work in the first instance but not the second? Aren't they both jQuery objects?
<span class='tst'>span</span>​
var tst = $('.tst');
console.log(tst.selector);
// prints '.tst'
$('.tst').each(function() { console.log(this.selector);});
// prints undefined​​​​​​​
this, in the context of the .each() loop, is not a jQuery object, so the selector property is undefined.
You need to make it a jQuery object first: $(this).selector
However, it should be noted that the selector property will return an empty string while inside the .each() loop.
Edit
If you absolutely need the selector property within the .each(), one option would be to cache your selector:
var cached = $('.tst');
cached.each(function() {
console.log(cached.selector); // Will display ".tst"
});
​
this != $(this)
In your first case tst is a reference to the jQuery object, but in the second this is simply the corresponding DOM element.
Within an .each() loop the .selector property is not available, however. To access '.tst' you can do $(this).attr("class") (when you use a class selector) -- though if you already use it in the each you can just cache it in a variable before hand.
Note that this will return all of the classes for that elements, so you can parse it later if it has more than one.
The best workaround based on your exact description is this:
var $tst = $(".tst");
$tst.each(function() {
console.log($tst.selector); //prints .tst
});
However I can't see any reason why you really need to do this.
Working Demo http://jsfiddle.net/wA6Yv/ or http://jsfiddle.net/a3CYR/2/
this != $(this)
If you keen: jQuery: What's the difference between '$(this)' and 'this'?
code
var tst = $('.tst');
console.log(tst.selector);
// prints '.tst'
$('.tst').each(function() {
alert($(this).text());
});
// prints undefined

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