HTML Template Doesn't Work with For-In Loop JavaScript - javascript

EDIT: Here's the JSFiddle for the following question.
http://jsfiddle.net/x28ojg6w/
So I'm trying to activate a template with JavaScript and it wasn't working for a while, and I finally fixed it by changing a For-In loop into a For loop in a seemingly unrelated block of code.
The following code is the For-In loop I changed to a for loop. The commented out code was the original code that didn't work and the uncommented for loop is the now working code. This code was used to change font size for text within all instances of a class element:
var release4 = document.getElementsByClassName("release-4");
// for (item in release4){
// release4[item].style.fontSize = "2em";
// };
for (var i = 0 ; i < release4.length ; i++) {
release4[i].style.fontSize = "2em";
}
This is the code I used to activate my template. It is not part of the release-4 class:
var tmpl = document.getElementById('hidden');
document.body.appendChild(tmpl.content.cloneNode(true));
And here is the HTML that goes with it:
<html>
<head>
<title>Manipulate the DOM</title>
</head>
<body>
<div id="release-0">
<p class="release-4"> Here is some text, add a class "done" to the parent div</p>
</div>
<div id="release-1">
<p>remove the #release-1 div</p>
</div>
<h1>Change this text to finish release 2</h1>
<div id="release-3">
<p class="release-4"> add CSS to this div</p>
</div>
<template id="hidden">
<div>
<h1> Congrats! You finished the challenge.</h1>
<img src="http://media.giphy.com/media/2UpzC3iPenf44/giphy.gif">
</div>
</template>
<script type="text/javascript" src="home_page.js"></script>
</body>
</html>
My question is why did changing the For loop make a difference? Thanks everyone!
All other code in the JS file only affect IDs release-0, release-1, and release-3, and the h1 tag. The class name, display, innerHTML, and background color were the only changes made to them.

If I console.log() item in the for in loop it yields:
0
1
length
item
namedItem
I think length, ìtem and namedItem make it error.
Updated:
With Array.from it works as expected.
var release4 = Array.from(document.getElementsByClassName("release-4"));
for (item in release4){
release4[item].style.fontSize = "2em";
};

Related

Webpage is infinitely loading when I use insertBefore() method

I am trying to modify the body section based on the tagName, using JavaScript. But my webpage is loading infinitely when I use insertBefore() method to insert a tag before the <h1> tag. This problem is not happening when I try to insert before some other elements. I am new to JS, please help me.
This is my HTML:
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title></title>
</head>
<body>
<p>Para 1</p>
<p>Para 2</p>
<h1 id="head1">Para 3</h1>
<p id="parax"></p>
<div id="div1">
<p>Hello</p>
</div>
<ul id="mylist1">
<li>Script</li>
<li>deep learning</li>
<li>software testing</li>
<li>Python programming</li>
<li>Database systems</li>
</ul>
<p id="firstp">I was supposed to be first.</p>
<input type="button" onclick="myFunc()">
</body>
<script type="text/javascript">
var cn=document.body.children;
for(var i=0;i<cn.length;i++){
if(cn[i].tagName=="DIV"){
var h1 = document.createElement("H1");
var text = document.createTextNode("h1 tag inserted");
h1.appendChild(text);
cn[i].appendChild(h1);
}
else if(cn[i].tagName=="UL"){
var lis= cn[i].childNodes;
for(var j=0;j<lis.length;j++){
if(lis[j].innerHTML=="Python programming")
lis[j].innerHTML="machine learning";
}
}
else if(cn[i].tagName=="H1"){
var p=document.createElement("P");
var text=document.createTextNode("New para inserted before");
p.appendChild(text);
document.body.insertBefore(p,cn[i]);
}
else
document.write();
}
</script>
</html>
At this line i am facing problem (I think so) :
document.body.insertBefore(p,cn[i]);
Because you with this line code:
document.body.insertBefore(p,cn[i]);
increase number of document.body.children and every time you insert child you and number of body children and you never not hit last index.
please add this to see:
document.body.insertBefore(p,cn[i]);
alert(document.body.children.length); // add this line after insertBefore
see every alert show the number of document.body.children was increase
Thanks to Mr #foad , I got the answer for my question. Actually the insertBefore() method is inside a for loop. So in every iteration, a new tag is added to the body and the length of the body increases by 1. This caused the infinite loading.
The correction is to add a break statement after the insertBefore method:
document.body.insertBefore(p,cn[i]);
break;
This terminates the loop after adding the <p> tag before <h1> tag.

Javascript loop to eliminate elements that do not start with certain value

I have links embedded inside .media-body .media-heading in the HTML example. I'm wanting to write JS to remove any link where the text does not start with the value attribute in the input element, in this case "A"
I've done a manual version below that checks the first A tag and manually removes the other A tag on the click of a button if the text doesn't start with "A". I need this to somehow loop through and do this automatically on page load but not sure how I do that. Any help is appreciated.
<!DOCTYPE html>
<html>
<body>
<input type="text" name="search" value="A" class="searchbox">
<div class="media-body">
<div class="media-heading">
A doc beginning with A
</div>
</div>
<div class="media-body">
<div class="media-heading">
Doc beginning with D
</div>
</div>
<button onclick="startFunction()">Remove wrong doc</button>
<script>
function startFunction() {
var az = document.getElementsByTagName("input")[0].getAttribute("value");
var getstart = document.getElementsByTagName("a")[0].innerHTML;
var searchletter = getstart.startsWith(az);
var myobj = document.getElementsByTagName("a")[1];
if(searchletter = az)
{
myobj.remove();
}
}
</script>
</body>
</html>
The second part of your question as how to do this automatically on page load is answered rather quickly. Conveniently you already wrapped the functionality inside it's own function - startFunction(). So all you have to do is execute that function after the <body> definition of your html code.
The first part isn't much more difficult as you also almost have anything you need set up yet. The only thing that's missing is looping over the HTMLCollection - more or less an array - retrieved by executing document.getElementsByTagName("a") using a simple for-loop.
There's a catch though: as you loop over the HTMLCollection and eventually remove an object from the DOM using .remove() you're ultimately changing the collection too. In other words, if you remove an object, the list shrinks by one element. To compensate your loop needs to start with the initial number of elements and decrement by one.
Here's an example:
function startFunction() {
let az = document.getElementsByTagName("input")[0].getAttribute("value");
let elements = document.getElementsByTagName("a");
let element;
for (let a = elements.length - 1; a >= 0; a--) {
element = elements[a];
if (!element.innerHTML.startsWith(az)) {
element.remove();
}
}
}
startFunction();
<input type="text" name="search" value="A" class="searchbox">
<div class="media-body">
<div class="media-heading">
A doc beginning with A
</div>
</div>
<div class="media-body">
<div class="media-heading">
Doc beginning with D
</div>
<div class="media-body">
<div class="media-heading">
Something completely different
</div>
</div>

JQuery each function to fill array with attributes from HTML images

I'm trying to load an array filled with the src attribute from a series of img tags in my HTML document.
HTML:
<html>
<head>
<title>
JQuery Slider
</title>
<link rel="stylesheet" type="text/css" href="css/main.css">
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.11.2/jquery.min.js"></script>
<script type="text/javascript" src="js/main.js"></script>
</head>
<body>
<div id = "wrapper">
<h1 class="dark-header">2014 Salt Lake Comic Con FanX</h1>
<div id="background-img">
<img src="img/img01.jpg"/>
</div>
<div>
<img src="img/img02.jpg"/>
</div>
<div>
<img src="img/img03.jpg"/>
</div>
<div>
<img src="img/img04.jpg"/>
</div>
<div>
<img src="img/img05.jpg"/>
</div>
<div>
<img src="img/img06.jpg"/>
</div>
<div>
<img src="img/img07.jpg"/>
</div>
<div>
<img src="img/img08.jpg"/>
</div>
<div>
<img src="img/img09.jpg"/>
</div>
<div>
<img src="img/img10.jpg"/>
</div>
</div>
</body>
</html>
JQuery:
$(document).ready(function() {
var source = new Array();
$('img').each(function(attr) {
source.push($('img').attr('src'))
});
console.log(source)
});//end document.ready
The output to the console is an array of 10 elements, but only using the first img attribute. I'm not sure how to get the each function to go through all elements and push them to the array.
Your issue is that $('img').attr('src') will always return the value of the first element in the collection of elements.
As pointed out in comments , you need to look at specific instances within your loop
Another way you can do this is using map() which will create the array for you
var source = $('img').map(function(){
return $(this).attr('src');
}).get();
DEMO
You could try something like this:
var source = [];
$('img').each(function() {
source.push( this.getAttribute('src') );
});
In your each code, you re-select the entire group with $('img') so it is only adding the first one of THAT Selection to your array.
OR
If you aren't using jQuery for anything else, you could do it in straight javascript like this:
document.addEventListener('DOMContentLoaded', getImgAttr);
var source = [];
function getImgAttr() {
var imgs = document.querySelectorAll('img');
[].forEach.call(imgs, function( img ) {
source.push( img.src);
});
}
you need to use 'this' while inside the loop to reference the image, otherwise you are getting the reference to first 'img ' tag.
it should be like this:
$('img').each(function(attr) {
source.push($(this).attr('src'))
});
Your callback function needs to accept a second param...
The first param is the current index of the array and the second param is the object at that index.
You may also utilize the keyword this as suggested above.
Based on my answer your code would look like this:
$('img').each(function(i, img) {
source.push($(img).attr('src'));
// alternatively -> source.push($(this).attr('src'));
});
A second option you may like and puts what you're trying to do onto a single line would be to use the jQuery map function...
var source = $.map($('img'), function(img) { return $(img).attr('src'); });

use html5 output tag to display javascript variables?

Sorry if this is a silly question, but I've been trying to use AJAX to display my javascript variables in 'real time' with little luck. I'm definitely a beginner though so this could be the problem haha- When I see the AJAX code, it always seems to require an additional url that it refreshes, but I just want to refresh the javascript variables on click.
http://jsfiddle.net/bagelpirate/m9Pm2/
<script>
var one = 0;
var two = 0;
var three = 0;
</script>
<body>
<div id="div_1">
One: <script>document.write(one)</script> |
Two: <script>document.write(two)</script> |
Three: <script>document.write(three)</script>
</div>
<div id="div_2">
<img id="mine" src="https://si0.twimg.com/profile_images/3170725828/ac1d6621fc3c3ecaa541d8073d4421cc.jpeg" onclick="one++;" />
<img id="forest" src="http://blogs.dallasobserver.com/sportatorium/No.%202.png" onclick="two++;" />
<img id="farm" src="https://si0.twimg.com/profile_images/3732261215/bd041d1f0948b6ea0493f90507d67ef2.png" onclick="three++;" />
</div>
</body>
As you can see in the above code, when a user clicks one of the images, I want to increment the count and display it at the top of the page. I found the HTML5 output tag, and was wondering if it's possible to use this to display the javascript variable in real time? Everything I've read seems to imply it can't be done because the output tag only works on forms? Anyway, I figured it couldn't hurt to ask!
Thanks for your time!
You shouldn't use document.write to write to the DOM after it's finished loading. You have tagged your question with jQuery, so I'll assume you can use that to update things. Instead, update the DOM from within your script block. Here is an example that might help you get started.
http://jsfiddle.net/prxBb/
<script type="text/javascript">
$(function() {
var one = 0;
var two = 0;
var three = 0;
$('img#mine').click(function() {
one++;
$('span#one').html(one);
});
$('img#forest').click(function() {
two++;
$('span#two').html(two);
});
$('img#farm').click(function() {
three++;
$('span#three').html(three);
});
});
</script>
<body>
<div id="div_1">
One: <span id="one"></span> |
Two: <span id="two"></span> |
Three: <span id="three"></span>
</div>
<div id="div_2">
<img id="mine" src="https://si0.twimg.com/profile_images/3170725828/ac1d6621fc3c3ecaa541d8073d4421cc.jpeg" />
<img id="forest" src="http://blogs.dallasobserver.com/sportatorium/No.%202.png" />
<img id="farm" src="https://si0.twimg.com/profile_images/3732261215/bd041d1f0948b6ea0493f90507d67ef2.png" />
</div>
</body>
Maybe you should try putting all your variables inside a named object, iterating through it at predefined interval and displaying the values.
var varContainer = {
one:0,
two:0,
three:0
};
jQuery("#div_2 img").on('click',function(){
jQuery.each(varContainer,function(key,value){
//Add key + value to the DOM
if(jQuery("."+key+value).length<1)
jQuery("#div_2").append("<div class='"+key+value+"'></div>");
var newHtmlVal= "<p><span>Var name: "+key+"</span><br><span>Value: "+value+"</span>";
jQuery("."+key+value).html();
});
});
HTML
<div id="div_2">
</div>
Of course the script could be upgraded to look through each variable recursivley in case of nested objects/arrays...
Hope this helps!

Citing a text area?

I'm just getting started in programming and somehow can't come up with any sensible approach to the following problem, so any help would be greatly appreciated! I have a .html file structured like this:
<head>
<title>ABC</title>
</head>
<body>
<div class="norm">
...
<span class="jnenbez">13</span>
....
<div class="Absatz">text</div>
<div class="Absatz">text</div>
<div class="Absatz">CITE HERE**</div>
The "norm" div is the one parent node. The "jnenbez" span and the "Absatz" divs are inside the "norm" div, but how deeply they are nested can vary. Now I want to cite the "CITE HERE" area, meaning to generate the output of "jnenbez 13 Absatz 3 ABC" - meaning getting the text content of the "jnenbez" span of the same "norm" div, getting the index number of the "Absatz" div, since it is the third child "Absatz" of the "norm" div and getting the content.
1) How could I give this string to the user, so he could copy paste it somewhere else? It seems it is not easily possible to modify the copy+paste behavior of Firefox. An obvious solution would be to put the output in brackets like [jnenbez...] at the end of each divs text content, but that would reduce readability of the html...
2) Is it even possible to automatically generate this output via JQuery?
Not sure about a good way to store/display the info.
Also, unsure of what other mark-up you would have in the class='norm' container. This is vitally important and impacts entirely the shape of the useful solution.
I've assumed a particular structure - one that says the first contained span is one of interest. Another assumption is that the only divs in the container are of interest and need to be counted.
I'm sure you can break it easily enough. :D
<!DOCTYPE html>
<html>
<head>
<script>
function onBtnPress(element)
{
var result;
var cont = element.parentNode;
var span = cont.getElementsByTagName('span')[0];
result = span.className + " ";
result += span.innerHTML + " ";
var divList = cont.getElementsByTagName('div');
result += divList[0].className + " ";
result += divList.length+" ";
result += document.title;
cont.getElementsByTagName('p')[0].innerHTML = result;
}
</script>
<title>ABC</title>
</head>
<body>
<div class="norm">
<span class="jnenbez">13</span>
<div class="Absatz">text</div>
<div class="Absatz">text</div>
<div class="Absatz">CITE HERE**</div>
<button onclick='onBtnPress(this);'>click me</button>
<p>[string here]</p>
</div>
<div class="norm">
<span class="Crapple">8</span>
<div class="ipod">worst</div>
<div class="ipod">music</div>
<div class="ipod">player</div>
<div class="ipod">I ever</div>
<div class="ipod">bought</div>
<div class="ipod">CITE HERE**</div>
<button onclick='onBtnPress(this);'>click me</button>
<p>[string here]</p>
</div>
</body>
</html>

Categories

Resources