Javascript change width of div onclick - javascript

I'm trying to do three things onclick:
have element with id="notes_content" change display:none to display: block
have element with id="oct" change width = "1190px" to width = "550px"
have elements with class="oct_days" change width = "168px" to width = "73px"
Fiddle of full code: http://jsfiddle.net/ascottz/jX3wh/
The first two happen, but the third does not. I suspect it is a syntax error, but can't catch it myself.

getElementsByClassName returns an array of dom elements, it is not a single instance. You must loop over the array and style each element.
Have a look at the updated fiddle.
for( var i = 0; i < days.length; i++ ){
days[i].style.width = "73px";
}
http://jsfiddle.net/jX3wh/4/

document.getElementsByClassName returns somewhat an array of elements, so you cannot simply refer to it as a DOM element in hope that it will work as you refer to each element of the collection (that is possible in jQuery, btw), so you have to use the foreach loop (doesn't matter how are you gonna achieve this -- via simple for(), or for(x in y), or any other way).
I usually use Array.forEach function, but the specific type of an array returned by the document.getElementsByClassName does not have such function in prototype, so you have to use [].forEach.call(inWhat,function(what){}) syntax, or fallback to for(...) syntax.
Check out this: http://jsfiddle.net/jX3wh/1/
Dunno if it works.

Also, what the f is this???
<div onclick="javascript:showDiv();" class="oct_days">
I am really very surprised this works. You should use onclick="showDiv()" instead, I think.
Somebody, please, tell me how does it work!

Related

classList.remove is removing elements from a HTMLCollection?

I'm encountering some very strange behaviour with JavaScripts new classList API, say we have the following HTML code:
<p class="testing">Lorem Ipsum</p>
<p class="testing">Lorem Ipsum</p>
And the following JavaScript code:
var elements = document.getElementsByClassName("testing");
alert(elements.length);
elements[0].classList.remove("testing");
alert(elements.length);
The first alert will give you a value of 2, whilst the second alert returns 1.
It appears that removing the class from the element is also removing it from the elements HTMLCollection, which makes absolutely no sense to me.
You can see an example of this code HERE.
I encountered this problem when trying to remove a certain class from some elements using code like below:
var elements = document.getElementsByClassName('testing');
var elementsLength = elements.length - 1;
for(var i = 0; i <= elementsLength ; i++)
{
elements[i].classList.remove('testing');
}
Say we have two elements like in the example above, the loop runs successfully the first time, but the second time it's looking for an element in the HTMLCollection that no longer exists, so I get something like "TypeError: elements[i] is undefined".
You can see an example of the above code HERE
This is frustrating to say the least, I can't understand why/how classList.remove could effect what is effectively an array set only once before the classList.remove function is called. I can't even seem to find anything about this behaviour online.
Am I doing something crazy? Or has I unearthed some strange hidden feature of the classList api that no one knows about?
The collection returned by document.getElementsByClassName is live so if an element doesn't have that class anymore it will be removed from the collection.
You can either create a non-live copy of the collection:
var elements = [].slice.call(document.getElementsByClassName('testing'));
Or take in account that it's live:
while (elements.length) elements[0].classList.remove('element-focus');
Using document.getElementsByClassName returns a live HTMLCollection:
An HTMLCollection in the HTML DOM is live; it is automatically updated when the underlying document is changed.
Thus (as described in plalx's answer) if you remove an element's class, the element is removed from an HTMLCollection based on that class.
Instead you could use document.querySelectorAll which returns a static NodeList collection:
The Document method querySelectorAll() returns a static (not live) NodeList representing a list of the document's elements that match the specified group of selectors.
So your code would change from
var elements = document.getElementsByClassName("testing");
with the class name "testing" as an argument, to
var elements = document.querySelectorAll(".testing");
with the class selector ".testing" as an argument.
And then you could iterate over elements which would be a static NodeList.

Javascript Compare Objects to Elements

http://jsfiddle.net/PhilFromHeck/KzSxT/
In this fiddle, you can see at line 38 in the Javascript that I've attempted to make a comparison that isn't working. I believe it because one of the variables is an Object, where the other is an Element; does anyone have any advice as to how I can can find a match between these two?
menuID[0] = document.getElementById('menuOne');
menuID[1] = document.getElementById('menuTwo');
menuID[2] = document.getElementById('menuThree');
menuID[3] = document.getElementById('menuFour');
$('.menu').mouseenter(function () {
for (var i = 0; i < 3; i++) {
if(menuID[i] == $(this)){
//this condition is not met, there's an alert which will add more detail in the fiddle
}
}
}
Method document.getElementById returns a DOM element an not a jQuery object. In the mouseenter event handler this refers to a DOM element as well.
So in order to compare them you shouldn't convert this to a jQuery object:
if (menuID[i] === this) { ... }
You want to use jQuery's .is() for this.
if($(this).is(menuID[i])){
A few issues I see here:
One is simply that, in your jsfiddle, the first 4 lines of code that you list aren't running before the bottom block runs. I'm not sure why you have both an init function that you attach to window.onload and a document.ready() function; but you'll want to make sure that init runs.
Secondly; as VisioN said, I think the main issue is that you're trying to compare a jQuery wrapper around a DOM element $(this) with a DOM element (the result of getElementById). As he says, this == menuID[i] will work.
At a design level, why not simply use the id to identify the element? this.id will give you the the id; why not simply use that to determine which menu div you're looking at?

How to use JavaScript's setattribute to affect multiple elements?

I have many div with the class publish_0 that I would like to change to publish_1 on click of a button.
Right now I use this but it only change one item.
How to I apply the setattribute to all item that have the publish_0.
document.querySelector('.publish_0').setAttribute("class", "publish_1");
You need to use a loop to iterate over all the elements and set their class attribute value individually:
var els = document.querySelectorAll('.publish_0');
for (var i=0; i < els.length; i++) {
els[i].setAttribute("class", "publish_1");
}
For when you can't use jQuery but want the convenience of something similar, you can do the following. Add the following code to the top of the file or somewhere else easily visible.
NodeList.prototype.forEach = NodeList.prototype.forEach || Array.prototype.forEach;
Now in your code you can do this:
document.querySelectorAll('body,main,article,[class*=content],[class*=center]')
.forEach((function(x){ x.setAttribute("style","width:1920px");}))
Or even nicer yet, if the browser supports ECMAScript2015 you can use arrow syntax:
document.querySelectorAll('[class*=content]')
.forEach( x=> x.setAttribute("style","width:1200px"))
You can put the statement all on one line if you'd like.
You can use this with jquery:
$(".publish_0").attr("class", "publish_1")
Alternatively, use getElementsByClassName and loop through the DOM elements returned.

Strange ie behaviour with jquery inArray

Hello this seems to be working on IE8 :
var clsName = link.parents("div.fixed_column").attr("class").split(" ");
if($.inArray("column_one", clsName)
While this one reports error (Object expected errror in jquery).
var clsName = link.parents("div.fixed_column").attr("class");
What is the right way to do this? I thought purpose of inArray was that jquery will handle cross browser issues.
Unfortunately, this is indirectly answering your question, but... You seem to be looking to detect if an element has a class, and since you're already using jQuery, just use the hasClass method - http://api.jquery.com/hasClass/
For your specific code, try:
if (link.parents("div.fixed_column").hasClass("column_one")) {
// It has the "column_one" class
}
The more immediate answer to your question is that link.parents("div.fixed_column").attr("class") returns a single string. When the jQuery selector (div.fixed_column) returns multiple elements, which is very possible when using classes, using jQuery methods that get information (like .attr, using one parameter...to "get" the value) return the first matched element's value only.
So say the selector matches 3 elements:
["<div id='div30' class='fixed_column div30_class'></div>",
"<div id='div2' class='fixed_column div2_class'></div>",
"<div id='div17' class='fixed_column div17_class'></div>"]
Then the value returned from .attr("class") will be: fixed_column div30_class because it's the first matched element.
I'm not sure, but I think you're expecting jQuery to return an array of all the matched elements' values, which it just doesn't. So that doesn't mean jQuery isn't handling cross-browser issues, it just means you need to look up what the method does/returns.
I could've sworn that jQuery 2.0 has options for doing what you want - directly from calling the getters (or something similar), but I can't find it anymore :( Maybe I'm remembering incorrectly. Anyways, you could easily use $.each and/or $.map to look at every matched element, but it depends on what you were really trying to do with it.
You can't read the attributes of multiple elements into an array with .attr("class"). But why don't you just target the desired class in the selector like this?
var cols = link.parents("div.fixed_column.column_one");
Then change your conditional to check for an empty set:
if(cols.length) { ...

Using insertBefore on an array of elements

I have an array of elements and I want use inserBefore on each of them as I iterate through the array. It's supposed to add the element-to-be-inserted after each of the elements in the array but it only adds it to the last element in the array. I thought it was a closure issue but even after using closures i still get the problem. Without closures I tested it by changing the class name to the key value that the array was on and it changed it no problem.
for(var i in elems){
var refElem = elems[i];
refElem.parentNode.insertBefore(elementToInsert, refElem.nextSibling);
}
Here's the code minus the closures. How do I get the elementToInsert added to each element in the array?
It's supposed to add the element-to-be-inserted after each of the elements
That's where the trouble arises, you cannot insert one element multiple times into the DOM. If you try to, it will just remove the element from the DOM before inserting it somewhere (again). So you will need to create distinct elements for each turn of the loop, for example by cloning your elementToInsert.
Btw, never use for…in-loops with arrays!
Just like Bergi said, the element you are inserting is actually being added and then removed from the node.
for(var i in elems){
var refElem = elems[i];
refElem.parentNode.insertBefore(elementToInsert.CloneNode(), refElem.nextSibling);
}
You can also inform the parameter 'deep', which will clone all the child nodes too.
https://developer.mozilla.org/en-US/docs/DOM/Node.cloneNode
just a little correction of the post before:
for(var i in elems){
var refElem = elems[i];
refElem.parentNode.insertBefore(elementToInsert.cloneNode(), refElem.nextSibling);
}
the function cloneNode() starts with a lowercase.

Categories