Why doesn't Jquery let me do this - javascript

document.getElementById("main").src = '02.jpg';
works
but
$('#main').src = '02.jpg';
doesn't

$("#main").attr("src", "02.jpg");

$('#main') returns a jQuery object, not a HTMLElement, therefore no src property is defined on the jQuery object. You may find this article useful.
Mike has shown one way of setting the src attribute (the way he has shown could probably be considered the most jQuery like way of doing it). A couple of other ways
$("#main")[0].src = '02.jpg';
or
$("#main").get(0).src = '02.jpg';

$('#main').src = '02.jpg';
The jQuery wrapper you get from $(...) does not reproduce all properties and methods of the DOM object(s) it wraps. You have to stick to jQuery-specific methods on the wrapper object: in this case attr as detailed by Mike.
The ‘prototype’ library, in contrast to jQuery, augments existing DOM objects rather than wrapping them. So you get the old methods and properties like .src in addition to the new ones. There are advantages and drawbacks to both approaches.

$("#main") is a collection of matches from a search. document.getElementById("main") is a single DOM element - that does have the src property. Use the attr(x,y) method for when you want to set some attribute on all of the elements in the collection that gets returned by $(x), even if that is only a single element as in getElementById(x).
It's akin to the difference between int and int[] - very different beasts!

Related

What does $($(this)) mean?

I saw some code around the web that uses the following statement
if ($($(this)).hasClass("footer_default")) {
$('#abc')
.appendTo($(this))
.toolbar({position: "fixed"});
}
What is the use of $($(this)) and why is that necessary here?
Yes, $($(this)) is the same as $(this), the jQuery() or $() function is wonderfully idempotent. There is no reason for that particular construction (double wrapping of this), however, something I use as a shortcut for grabbing the first element only from a group, which involves similar double wrapping, is
$($('selector')[0])
Which amounts to, grab every element that matches selector, (which returns a jQuery object), then use [0] to grab the first one on the list (which returns a DOM object), then wrap it in $() again to turn it back into a jQuery object, which this time only contains a single element instead of a collection. It is roughly equivalent to
document.querySelectorAll('selector')[0];, which is pretty much
document.querySelector('selector');
You can wrap $ as many times as you want, it won't change anything.
If foo is a DOM element, $(foo) will return the corresponding jQuery object.
If foo is a jQuery object, $(foo) will return the same object.
That's why $($(this)) will return exactly the same as $(this).
There is no specific need for double-wrapping and $($(this)) is exactly the same as $(this).
That said, I once found this double-wrapping in one file in my project, committed by another developer. Tracking the changes through revision, turned out that it started as $($(this).find('selector').first()) - that is, the result of some selector was wrapped to create a new object. Then for whatever reasons, the selector was removed and only the double-wrapping of this remained. Needless to say, on the next commit it was changed to $(this).
As explained before me, $($(this)) and $(this) are absolutely identical. jQuery returns the same jQuery object if you try to wrap it more than once.
Additionally, for performance considerations it is a good practice to reuse jQuery objects - it is quite expensive to create jQuery objects, especially the ones with complex selectors. Example:
var $this = $(this);
if ($this.hasClass("footer_default")) {
$('#abc')
.appendTo($this)
.toolbar({position: "fixed"});
}
Just google for 'jQuery best practices' - it will take a 30 min for you to learn these basics and you will use jQuery way more effectively.
There is no meainig of doing that.
The following code return the same:
console.log($($(this)).hasClass("footer_default"))
console.log($(this).hasClass("footer_default"))
a boolean value depenging on if the selected element has or not the class footer_default:
.hasClass( className )Returns: Boolean
Demo: http://jsfiddle.net/IrvinDominin/aSzFn/
$(this) and $($(this)) both return jquery object.
There is no difference between these two.

Can JQuery and Javascript be mixed together?

I am wondering if I could use query and javascript together so I could select an element by class with the javascript and then use javascript to work on that element. Sorry if that didn't make sense. Here is an example:
$('.nav_flag').src = "images/flags/"+userCountryLower+".gif";
Would that work, if not how do I get an element by class using regular javascript. Thanks!
EDIT:I know JQUERY is JavaScript but I was wondering if I could mix jquery selectors and javascript 'controller'-for a loss of a better word
To answer your question as asked, there are several ways to take a jQuery object, i.e., what is returned by $('some selector'), and get a reference to the underlying DOM element(s).
You can access the individual DOM elements like array elements:
// update the src of the first matching element:
$(".nav_flag")[0].src = "images/flags/"+userCountryLower+".gif";
// if you're going to access more than one you should cache the jQuery object in
// a variable, not keep selecting the same thing via the $() function:
var navFlgEls = $(".nav_flag");
for (var i = 0; i < navFlgEls.length; i++) { ... }
But you wouldn't manually loop through the elements when you can use jQuery's .each() method, noting that within the callback function you provide this will be set to the current DOM element:
$(".nav_flag").each(function() {
this.src = "images/flags/"+userCountryLower+".gif";
});
However, jQuery provides a way to set attributes with one line of code:
$(".nav_flag").attr("src", "images/flags/"+userCountryLower+".gif");
To answer the second part of your question, doing the same thing without jQuery, you can use .getElementsByClassname() or .querySelectorAll() if you don't care about supporting older browsers.
jQuery IS Javascript. You can mix and match them together. But you better know what you're doing.
In this case, you probably want to use .attr function to set value of attribute.
Use .attr() in jQuery, rather than mix the two here.
$('.nav_flag').attr('src', "images/flags/"+userCountryLower+".gif");
In many instances, it is fine to mix jQuery with plain JavaScript, but if you have already included the jQuery library, you might as well make use of it. Unless, that is, you have an operation which in jQuery would be more computationally expensive than the same operation in plain JavaScript.
You can do it with jQuery too:
$('.nav_flag').attr("src", "images/flags/"+userCountryLower+".gif");
keep in mind that jQuery is simply a library built upon javascript.
for any jQuery object, selecting its elements by subscription will return the corresponding dom element.
e.g.
$('#foo')[0] // is equivalent to document.getElementById('foo');
You need to add an index to the jQuery object to get the native Javascript object. Change:
$('.nav_flag').src = "images/flags/"+userCountryLower+".gif";
To:
$('.nav_flag')[0].src = "images/flags/"+userCountryLower+".gif";
To get elements by class name in Javascript you can use:
document.getElementsByClassName( 'nav_flag' )[0].src = "images/flags/"+userCountryLower+".gif";
To answer your question, you could use .toArray() to convert the jQuery object into an array of standard DOM elements. Then either get the first element or loop through the array to set all the elements with the class.
However, you could do this easier with pure jquery with attr or prop depending on the version:
$('.nav_flag').attr("src", "images/flags/"+userCountryLower+".gif");
Or use pure javascript:
if (navFlagElements = document.getElementsByClassName("nav_flag") && navFlagElements.length > 0) {
navFlagElements[0].src = "images/flags/"+userCountryLower+".gif"
}

In DOM is it OK to use .notation for getting/setting attributes?

In DOM, is it OK to refer to an element's attributes like this:
var universe = document.getElementById('universe');
universe.origin = 'big_bang';
universe.creator = null;
universe.style.deterministic = true;
? My deep respect for objects and their privacy, and my sense that things might go terribly wrong if I am not careful, makes me want to do everything more like this:
var universe = document.getElementById('universe');
if(universe.hasAttribute('origin')) then universe.origin = 'big_bang';
etc...
Is it really necessary to use those accessor methods? Of course it may be more or less necessary depending on how certain I am that the elements I am manipulating will have the attributes I expect them to, but in general do the DOM guys consider it OK to use .notation rather than getters and setters?
Thanks!
For XML documents, you must use getAttribute/setAttribute/removeAttribute etc. There is no mapping from JavaScript properties to DOM attributes.
For HTML documents, you can use getAttribute et al to access attributes, but it's best not to because IE6-7 has difficulties with it. The DOM Level 2 HTML properties are not only more reliable, but also easier to read.
It's unclear whether you're using XML or HTML documents here. Clearly origin is not an HTML attribute; ‘custom’ elements and attributes like this should not be included in HTML documents. But it's unclear what universe.style.deterministic refers to; you wouldn't get a CSS style lookup mapped without an HTML style attribute.
Yes, it's fine ;-)
If there's an attribute in the DOM, you can set it or get it, directly.
No private or read-only elements or anything. By the way, JavaScript doesn't have a 'then' keyword.
Due to cross browser issues I always use getAttribute and setAttribute:
if(!universe.getAttribute('origin'))
{
universe.setAttribute('origin', 'big_bang');
}
I don't recall the specifics but I have had problems with the property style universe.origin and dynamically created DOM elements.
No, it's not fine to do so. Most properties of DOM objects can be overwritten. You won't ruin the browser's behavior, since it doesn't use the DOM API. But you will ruin your JS scripts if they attempt to use the overwritten property in its original meaning.
My own way of doing things, when I have several attributes to attach to an object (as opposed to a single flag or link), is to create a custom object and then link it from the DOM element:
var Universe = {
origin: "big_bang",
creator: null,
style: { deterministic: true }
};
document.getElementById('universe')._universe = Universe;

How to add/update an attribute to an HTML element using JavaScript?

I'm trying to find a way that will add / update attribute using JavaScript. I know I can do it with setAttribute() function but that doesn't work in IE.
You can read here about the behaviour of attributes in many different browsers, including IE.
element.setAttribute() should do the trick, even in IE. Did you try it? If it doesn't work, then maybe
element.attributeName = 'value' might work.
What seems easy is actually tricky if you want to be completely compatible.
var e = document.createElement('div');
Let's say you have an id of 'div1' to add.
e['id'] = 'div1';
e.id = 'div1';
e.attributes['id'] = 'div1';
e.createAttribute('id','div1')
These will all work except the last in IE 5.5 (which is ancient history at this point but still is XP's default with no updates).
But there are contingencies, of course.
Will not work in IE prior to 8:e.attributes['style']
Will not error but won't actually set the class, it must be className:e['class'] .
However, if you're using attributes then this WILL work:e.attributes['class']
In summary, think of attributes as literal and object-oriented.
In literal, you just want it to spit out x='y' and not think about it. This is what attributes, setAttribute, createAttribute is for (except for IE's style exception). But because these are really objects things can get confused.
Since you are going to the trouble of properly creating a DOM element instead of jQuery innerHTML slop, I would treat it like one and stick with the e.className = 'fooClass' and e.id = 'fooID'. This is a design preference, but in this instance trying to treat is as anything other than an object works against you.
It will never backfire on you like the other methods might, just be aware of class being className and style being an object so it's style.width not style="width:50px". Also remember tagName but this is already set by createElement so you shouldn't need to worry about it.
This was longer than I wanted, but CSS manipulation in JS is tricky business.
Obligatory jQuery solution. Finds and sets the title attribute to foo. Note this selects a single element since I'm doing it by id, but you could easily set the same attribute on a collection by changing the selector.
$('#element').attr( 'title', 'foo' );
What do you want to do with the attribute? Is it an html attribute or something of your own?
Most of the time you can simply address it as a property: want to set a title on an element? element.title = "foo" will do it.
For your own custom JS attributes the DOM is naturally extensible (aka expando=true), the simple upshot of which is that you can do element.myCustomFlag = foo and subsequently read it without issue.

Prototype get by tag function

How do I get an element or element list by it's tag name. Take for example that I want all elements from <h1></h1>.
­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­
document.getElementsByTagName('a') returns an array. Look here for more information: http://web.archive.org/web/20120511135043/https://developer.mozilla.org/en/DOM/element.getElementsByTagName
Amendment: If you want a real array, you should use something like Array.from(document.getElementsByTagName('a')), or these days you'd probably want Array.from(document.querySelectorAll('a')). Maybe polyfill Array.from() if your browser does not support it yet. I can recommend https://polyfill.io/v2/docs/ very much (not affiliated in any way)
Use $$() and pass in a CSS selector.
Read the Prototype API documentation for $$()
This gives you more power beyond just tag names. You can select by class, parent/child relationships, etc. It supports more CSS selectors than the common browser can be expected to.
Matthias Kestenholz:
getElementsByTagName returns a NodeList object, which is array-like but is not an array, it's a live list.
var test = document.getElementsByTagName('a');
alert(test.length); // n
document.body.appendChild(document.createElement('a'));
alert(test.length); // n + 1
You could also use $$(tag-name)[n] to get specific element from the collection.
If you use getElementsByTagName, you'll need to wrap it in $A() to return an Array. However, you can simply do $$('a') as nertzy suggested.

Categories

Resources