Change classname of div - javascript

In my page I want to change the class name of the div whose id is answer1 in div id=question. How can I do that? Thanks.
$('question1 answer1').addClassName('new_name');
<div id="question1">
<div id="answer1" class="old_name">
</div>
</div>
<div id="question2">
<div id="answer2" class="old_name">
</div>
</div>

So, as it has been pointed out, any selector method requires an iterator of some sort, so you can not just apply a method to all objects returned. You will notice in the documentation for Element.select that this is supposed to alleviate having to explicitly convert the object to an array, but I have not had luck with this on jsfiddle. However, I did try the following:
$('answer2').addClassName('new_name');
​
And it worked just fine. I don't know if the issue is that you are trying to traverse the DOM in your original element object (by using question1 answer1) and this requires the object/array iterator, or if it's just a hiccup elsewhere in the code. But in your specific example, since you know the id of the actual element you want to change the class of, the above code should work fine without specificing the parent element or using an array index of any kind.
I will admit that prototypejs threw me off because they use the same method names for the Element objects as Enumerable objects, so I saw the first instance of select and thought it looked pretty straight forward. Having now seen that almost every class/method requires you to set up a selector and convert it or manually traverse it, I will definitly say that this would be much easier with jquery and that your initial comment that they are almost the same is specifically not true in this scenario. Perhaps protojs offers some features that jquery does not, perhaps your code is tied to protojs (I worked on a project for a year that had to use YUI, which is a much bigger nightmare, trust me), but jquery is set up to play nice with prototypejs, so in cases like these, I'd consider using both. In jquery, the code would have been:
jQuery.noConflict(); // Avoids $ fight between jquery and prototypejs
jQuery( '#question1 #answer1' ).addClass('new_name');
or, to remove the old one first:
jQuery.noConflict(); // Avoids $ fight between jquery and prototypejs
jQuery( '#question1 #answer1' )removeClass('old_name').addClass('new_name');
Also, prototype has a toggleClass method that is probably also unnecessarilly esoteric, but maybe you should read up on: toggleClassName
And I wouldn't be this pissy about wasting my time on this (because I don't like to consider getting stuck learning a new framework a waste of time) except that their documentation, while attractive, has the worst examples I've ever seen. They all assume you have some fundamental idea without ever a friendly real world example or hyperlink to the difference between an instance and a class, and their examples distinguishing the two are identical. I'm definitely going to take some time out later today to find the real best answer to your question, out of spite and pride, if nothing else, but if it really comes down to having to iterator every time, just use vanilla js and use this framework when it's actually useful.

Simply $('answer1') will get you a reference to the div element that you want. The $ function returns an element with the given id string (or null if none was found). Note that you don't use a selector string when using $ - it only operates on ids.
The $$ function takes in a CSS selector string and returns an array of all matching elements, or an empty array if nothing matched. If you wanted or needed to go that route, you could locate the same div like this:
$$('#question1 .answer1')[0]
Once you have your element reference using either of the above methods, you can use addClassName or removeClassName or any other element methods available.

Related

Triggering change on input

I have written some code that changes an input quantity on a magento 1.9 ecommerce website.
jQuery("input.qty").val("10");
The problem is the javascript that triggers the total to update doesn't fire. I have found the code responsible and it looks like this:
(function() {
var qtyFields = $('super-product-list').select('input.qty');
qtyFields.each(function(el) {
el.observe("change", updateGroupedPrice);
});
Event.observe(window, "load", updateGroupedPrice);
function updateGroupedPrice() {
//do stuff
}
})();
I think this is using prototype.js but I tried to isolate it in a codepen but couldn't get it working.
I have tried to trigger the change event like so:
jQuery("input.qty").trigger("change")
But it does not work. I also ran through a load of other events but in the dev tools it shows the code listening on "change".
Does anyone know why I can't trigger the change?
Since the page is using Prototype.js, you ought to keep using that to trigger your change. If you introduce jQuery into this, you're a) loading another complete duplicate of what Prototype already does, and b) asking for a lot of trouble isolating the fact that $() is a method in both libraries.
Your jQuery is a little fishy to me, too. You're setting the value of one picker (I imagine) and yet you are addressing it with a classname, so potentially there is more than one select.qty in the page, and all of them will change to value 10, firing off (potentially) multiple callback functions.
The Prototype code you see here is setting up a "listener" for changes on what you would address in jQuery as$(#super-product-list input.qty) inputs.
jQuery always treats $() as returning an array of objects, and thus all of its methods act on the array, even if it only contains one member. Prototype has two different methods for accessing elements in the DOM: $('some_id'), which always returns one element (or none, if no match), and $$('some css selector'), which always returns an array (of zero or more matching elements). You would write (or use native) callback methods differently, depending on which accessor you used to gather the element(s).
If you want to change one of these inputs, you will need to isolate it before you set its value.
Let's say there are three select pickers with the classname qty in your #super-product-list element. You want to change the third one to 10:
$('super-product-list').select('input.qty').last().setValue('10');
Or, much smarter than this, you add an ID to the third one, and then your code is much shorter:
$('quantity_3').setValue('10');
In either case, this will send the "change" event from your select, and the updateGroupedPrice method will observe that and do whatever you have coded it to do.
You won't need to (and should not ever) trigger the change event -- that's a "native" event, and the browser owns it. jQuery's trigger() (which is fire() in Prototype, is used exclusively for "synthetic events", like you see in Bootstrap: show.bs.modal, hide.bs.modal, etc. You can spot these by the punctuation in their names; usually dots or colons to namespace the events and avoid collisions with other code.
Finally, if you really, really, really wanted to change every single #super-product-list select.qty element on the whole page to '10', you would do this in Prototype.js:
$$('#super-product-list select.qty').invoke('setValue', 10);

How does jQuery selection work with a variable that hasn't been declared?

Today I found code online like this.
Here's a simplified version of what I don't understand.
<div id="foo"></div>
$(foo) //gets the correct element
How does foo not throw an error and select the right DOM element?
Honestly, I did not know this was possible but it is a feature of javascript. You should read this stackoverflow answer which basically says, do NOT use this feature.
I don't have a detailed explanation but I'll say this. It has nothing to do with jQuery. This is purely a javascript feature.
Run this test to understand. Create an index.html file and then open up the console in developer tools. Type out the id name on the element and javascript will print out the javascript.
index.html
<html>
<body>
<div id="foo"></div>
</body>
</html>
In the console log, write out foo and click enter. Chrome console should print out <div id="foo"></div>.
In your example, you should fix the typos so you get a clearer understanding. I may not be using the official jQuery verbiage here, you should read the docs, but this should make some sense of the example.
These are not variables, they are jQuery objects.
The javascript elements like $( '#overlay' ) are calls to the jQuery function with a selector which can be the same as a CSS selector. The return value is a jQuery object, and jQuery's method .addClass() is being invoked right away on the returned object.
In your example, the selectors are ids, but tag names, classes and pseudo classes work too, and you can even wrap javascript references to DOM elements in $( ... ) to use jQuery functions. jQuery returns an object that includes many member functions, not just the .addClass() method shown here, and some selectors will return a collection not just a single item. For instance, $( 'a' ) returns a jQuery object with a reference to every link on the page.

Why does jQuery .after() not chain the new element?

I am curious why jQuery's .after() does not chain, or "provide you with," the new element that you create with it. It seems to me like it should, but I am no expert and was hoping someone could shed some light on why it's a bad idea. Here's an example to see what I would like from .after():
Here is some markup:
<div id="content1">
<p id="hello1">Hello</p>
</div>
<div id="content2">
<p id="hello2">Hello</p>
</div>
Here's what I want, but this replaces "Hello" with "World!":
$('#hello1').after('<p />').text('World!');
This does the job, but it sure is ugly:
$('#hello2').after('<p />');
var $newParagraph = $('#content2 p').last();
$newParagraph.text('World');
This is nicer, but I'm not entirely sold: (maybe I should be?)
$('#hello1').after( $('<p />').text('World') );
Note this is obviously a simplified example, that is, "<p>World!</p>" is not what I want to add, my real world problem is more complex than that.
Thanks for any thoughts.
Presumably .after() works as it does to allow you to chain more methods that would apply to the originally selected element(s):
$('#hello1').after( $('<p />').text('World') )
.before( $('<p />').text('Before text') )
.remove();
This keeps the behaviour consistent with other methods, so you don't have to try to remember which ones return the original object and which return some other object.
Note that in your case $('#hello1') selects exactly one element since you are selecting by id, but you can apply .after() to a jQuery object containing many elements to add (cloned) content after multiple elements:
$('div.someclass').after( $('<p/>').text('whatever') );
In which case in my opinion it definitely makes sense to keep the chaining context as the original jQuery object.
The .insertAfter() method might be closer to what you want:
$('<p/>').insertAfter('#hello1').text('World');
(It also returns the jQuery object it was applied to, but it does the insert in "reverse".)
You could write your own plugin method to return the element being added, but that would be confusing since it would work opposite to all the standard methods.
That's just how it is for most jQuery methods. It's better for jQuery to be consistent and return the original object.
The fix is this:
$('#hello1').after(
$('<p/>', { text: 'World!' })
);
or:
$('#hello1').after(
$('<p/>').text('World!')
);
or even:
$('<p/>').text('World!').insertAfter('#hello1');
The latter may actually be preferred since it does then continue to chain from the new <p> element.
It doesn't provide you with the created element because you don't always create an element, it would require a significant amount of processing power for JQuery to detect that a element is created and it makes much more sense to always have it return the element witch was the target of the operation.

jQuery Selectors, efficiency

I have been reading more lately about the efficiency of the different selector engines. I know that jQuery uses the Sizzle engine and this blog post about some jQuery stuff mentioned that the Sizzle engine will break apart your selector into an array then parse left to right.
It then, from right to left, begins deciphering each item with regular expressions. What this also means is that the right-most part of your selector should be as specific as possible — for instance, an id or tag name.
My question is whether it is more efficient to run a selector with just the ID specified or the tag name as well:
var div = $('#someId');
//OR
var div = $('div#someId');
Since I write my CSS in the div#someId form I tend to do my selectors the same way, am I causing Sizzle to perform extra work (assuming QuerySelectorAll is unavailable)?
jQuery and Sizzle optimize the #id selector [source] to document.getElementById(id). I think they aren't able to optimize it like this with the tag#id.
The first is faster.
BTW specifying the tag name for an #id selector is over-specifying, as there can be only one tag with a given id on the document. Over-specifying is slower even in CSS.
Rather than speculating, let's measure it!
Here's a test case with this page loaded, then matching a random element with both methods.
Make sure you scroll right down to the bottom.
http://jsperf.com/which-jquery-sizzle-selector-is-faster#runner
As you might expect, a plain id is faster than a tag qualified one (reduction to getElementByID). This is the same when using classes.
Selecting by ID is massively faster than selecting by class, mainly as IDs are guaranteed to be unique.
If you are using jQuery, you can assume a browser with getElementById. $('#someId') can be converted to document.getElementById('someId'). $('div#someId') won't be, so it will be faster to lose the tag name.
jsPerf demonstrating this. The difference is enormous.
var div = $('#someId'); //should be faster
jQuery will use getElementById() for the above selector
var div = $('div#someId'); //would probably preform slower due to finding all the divs first
jQuery will use getElementsByTagName(), then iterate though the array of elements for the above selector
You should also remember, tag names should definately be used with class selectors (whenever possible)
var div = $('div.myclass') //faster than the statement below
versus
var div = $('.myclass') //slower
JsPerf: http://jsperf.com/jquery-id-vs-tagname-id
The first one is going to be faster because it only has to check the id. The second one runs the same check AND has to make sure the tagname is correct. div#id won't give you the element with id id unless it is a div
You can see from the source code here: http://code.jquery.com/jquery-1.6.2.js in the function init.
The fastest selector is $('') which just returns an empty jQuery object immediately.
$('body') is next, which jQuery converts to document.body
The next is $('#id') which uses document.getElementById('id').
Any other selector such as $('div#id') will just become a call to $(document).find('div#id'). find() is very complex compared to any of those other solutions and uses Sizzle JS to select the div.

javascript - name or id of element

Is this.form.sel2 similar to document.getElementById('sel2')?
My select tag is as follows:
<select size=5 id="sub_player_ids" name="sub[player_ids][]">
And when I am putting the name of the tag, i.e, sub[player_ids][] in my javascript code, am getting a syntax error.
I am trying to find a workaround so that instead of using the name of the element, i want to use the id.
However using document.getElementById('sub_player_ids') is not working.
Thanks for any suggestion provided.
Please see my javascript code below:
<input type="button" value="-->"
onclick="moveOptions(this.form.sel1, this.form.sel2);" /><br />
<input type="button" value="<--"
onclick="moveOptions(this.form.sel2, this.form.sel1);" />
The id of your element is sub_player_ids, not sel2. So document.getElementById("sub_player_ids") would work.
You may also find that this.form["sub[player_ids][]"] would work. Using the quoted form lets you use things that you can't use in the literal form.
Something to beware of is that IE7 and earlier have a broken version of getElementById that will find things that use the given string as a name, rather than as an id, even if something later on the page actually uses it as an id. (Yes, really; more here.) Some libraries will work around that for you (jQuery does, for instance). And actually, speaking of libraries, a good library really can help work around all sorts of browser inconsistencies and provide a lot of handy utility functionality, letting you concentrate on your actual business problems. You might consider looking at jQuery, Prototype, YUI, Closure, or any of several others.
You can use bracket notation instead:
this.form['sub[player_ids][]']
...or getElementById(), with the right ID:
document.getElementById('sub_player_ids')
Use document.getElementById('sub_player_ids') to get that element.
You have the wrong id
document.getElementById('sub_player_ids')
verify that your options contains id, it would only be containing name with sel2

Categories

Resources