Appending to body with javascript - javascript

I have an assignment to make several bugs fly around the screen randomly, but I'm having problems getting divs to be added to the html body through javascript.
<head>
<title>Fly little bug! Fly!</title>
<script type="text/javascript">
/* <![CDATA[ */
var numBugs = 0;
var body = document.getElementsByTagName("body");
function bug(startX, startY, xSpeed, ySpeed){
var self = this;
this.xPos = startX;
this.yPos = startY;
this.xSpeed = xSpeed;
this.ySpeed = ySpeed;
this.divId = "bug" + numBugs;
this.div = document.createElement("div");
this.div.innerHTML = "test";
body.appendChild(self.div);
this.fly = function(){
self.xPos += self.xSpeed;
self.yPos += self.ySpeed;
}
this.fly();
this.flyInterval = setInterval(function(){ self.fly(); },5000);
numBugs++;
}
/* ]]> */
</script>
</head>
<body onload = "var bug1 = new bug(10, 20, 5, 3);">
</body>
</html>

I can see two problems.
The getElementsByTagName function returns an array of elements. You have to be explicit that you want the first element of the array.
var body = document.getElementsByTagName("body")[0];
You're essentially saying "give me all the tags in the document of type 'body'". It gives you a list of tags, and you have to get the first one even though there should only be one "body" in any HTML document. The [0] in the code above gives you the first one.
You are trying to access the body before it's created. The <script> occurs in the document before the <body> tag, so at the time the script is executed, the body doesn't exist. You need to move the call to getElementsByTagName inside the bug() function.

document.body.innerHTML += '<div>Div Content</div>';
Look into jQuery if you want to make simple DOM manipulation easier on yourself.

Related

DOM Manipulation Click Mouse Event

I was trying to change the color of the background of the web page with a mouse click, below are the lines for the same:
let bodyvar = document.querySelector('body');
bodyvar.addEventListener("click",generate);
function generate(){
bodyvar.style.backgroundColor = "red";
}
When I test individual lines in console it is selecting the body and the function and everything works correctly individually but not on the actual page.
I have just started leaning JS so am not sure what am missing here, will I also need to consider the co-ordinates that the mouse clicks on?
I suspect that the <body></body> is empty. Add some content, or define the width and height.
let bodyvar = document.querySelector('body');
bodyvar.style.minWidth = "100vw";
bodyvar.style.minHeight = "100vh";
bodyvar.addEventListener("click",generate);
function generate(){
bodyvar.style.backgroundColor = "red";
}
Alternatively, I can use <HTML> instead of <body>.
let bodyvar = document.querySelector('html');
bodyvar.addEventListener("click",generate);
function generate(){
bodyvar.style.backgroundColor = "red";
}

Dynamically increasing font size

I would like to increase the font size of the paragraph as well as the font size of the number in the button.
I copied and pasted my sizer function from StackOverflow (a few alterations) and thought it would work and still can't get it to work. Can someone help?
Since I've spent so much time on just the first part, as a beginner programmer, I'm wondering what I am missing. Does anyone have any ideas from my code or their experience as to what I might be missing?
Thanks as always.
<html>
<button onclick='incrementer(); sizer()' id='count' value=0 />0</button>
<p id='test'>a</p>
<script>
clicks = 0
incrementer = function () {
clicks += 1
click = document.querySelector("#count").textContent = clicks;
click.innerHTML = document.getElementById("count").value = document.getElementById('test');
}
sizer = function changeFontSize() {
div = document.getElementById("test");
currentFont = div.style.fontSize.replace("pt", "");
div.style.fontSize = parseInt(currentFont) + parseInt(clicks) + "pt";
}
</script>
</html>
Some things here:
I woudn't append two functions to your onclick here. Just append one and call your second function from the first one that gets fired via onclick. That looks a lot more tidy
Don't forget to put var before every variable, without it's not valid JavaScript
I didn't quite understand what you tried with your currentFont variable, so I removed it. It's not necessary and causes the script to not working correctly
<html>
<button onclick='incrementer()' id='count' value=0 />0</button>
<p id='test'>a</p>
<script>
var clicks = 0;
var incrementer = function() {
clicks += 1;
var click = document.querySelector("#count").textContent = clicks;
click.innerHTML = document.getElementById("count").value = document.getElementById('test');
sizer();
}
var sizer = function changeFontSize() {
var div = document.getElementById("test");
div.style.fontSize = parseInt(clicks) + "pt";
}
</script>
</html>
Here's a from-scratch version that does what you're asking for. I'll point out a few things that I did to help you out.
https://codepen.io/anon/pen/VBPpZL?editors=1010
<html>
<body>
<button id="count">0</button>
<p id="test">
Lorem Ipsum is simply dummy text of the printing and typesetting industry.
</p>
</body>
</html>
JS:
window.addEventListener('load', () => {
const button = document.querySelector('#count');
const paragraph = document.querySelector('#test');
const startingFontSize = window.getComputedStyle(document.body, null)
.getPropertyValue('font-size')
.slice(0, 2) * 1;
let clicks = 0;
button.addEventListener('click', () => {
clicks++;
// this is a template literal
// https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Template_literals
const fontSize = `${startingFontSize + clicks}px`;
button.innerHTML = clicks;
button.style.fontSize = fontSize;
paragraph.style.fontSize = fontSize;
});
});
The code runs when the page is loaded, so we attach an event listener on the window object listening for the load event.
We then store references to the button and the paragraph elements. These are const variables because their values won't change. This also limits their scope to the containing function.
We get the initial font size for the body element, because in this example we aren't explicitly setting a base font in css so we're just using the one for the document. getComputedStyle is a somewhat expensive operation, and in this case we only need to get it in the beginning because it won't change, so we also store it as a const. The value is returned as a string like "16px" but we need the number, hence the slice and multiplying by one to cast the string into a number. parseInt would also do the same thing.
Notice that clicks is defined with let. This means that the variable can be changed. var still works of course, but in modern practices its best to use const and let when declaring variables. This is partly because it forces you to think about what kind of data you're working with.
We add an event listener to the button element and listen for the click event. First, we increment the clicks variable. Then we declare fontSize using a template literal which adds our new clicks count to the startingFontSize and "px" to get a string.
Finally, the innerHTML value of the button element is updated. Then we update the fontStyle property for both elements.
The issue here is that there is no initial value for the fontSize of your <p> tag so div.style.fontSize returns an empty string.
You can use window.getComputedStyle instead of div.style.fontSize and you will get the current fontSize.
There is already a post explaining this method
https://stackoverflow.com/a/15195345/7190518
You don't have an initial font-size style on your <p> tag, so it div.style.fontSize is always empty. Also, best practice is to always use var when introducing new variables in javascript.
One good trick to help debugging things like these is to use console.log() at various points, and see whats coming out in your browser console. I used console.log(div.style.fontSize) and the answer became clear.
Working below after adding <p style='font-size:12px'>a</p>:
<html>
<button style='font-size:12px;' onclick='incrementer(); sizer()' id='count' value=0 />0</button>
<p id='test' style='font-size:12px;'>a</p>
<script>
var clicks = 0
incrementer = function () {
clicks += 1
click = document.querySelector("#count").textContent = clicks;
click.innerHTML = document.getElementById("count").value = document.getElementById('test');
}
var sizer = function changeFontSize() {
var div = document.getElementById("test");
var btn = document.getElementById("count");
var newSize = parseInt(div.style.fontSize.replace("pt", "")) + parseInt(clicks);
div.style.fontSize = newSize + "pt";
btn.style.fontSize = newSize + "pt";
}
</script>
</html>
I don't understand the logic of this solution, but you can simplify it avoiding to use a lot of var (anyway always prefer let or const if you don't need to change), using a single function and writing less code.
function increment(e){
const ctrl = document.getElementById('test');
let current = parseInt(e.dataset.size);
current += 1;
e.innerHTML = current;
e.dataset.size = current;
ctrl.style.fontSize = current + 'pt';
}
<button onclick="increment(this);" data-size="20">20</button>
<p id='test' style="font-size:20pt;">A</p>

Appending script to HTML via JS

I am trying to add run an external script that basically appends HTML elements to the page. I can't just use a script tag as I need it to run asynchronously, however when I use <script async src="..."> the script appends the elements to the bottom of the page, rather than the class that it's being called in.
Therefor I've created this script to append the external script tag to the page.
var x = document.createElement("SCRIPT");
x.src = '//rss.bloople.net/?url=https%3A%2F%2Fwww.coindesk.com%2Ffeed%2F&limit=5&showicon=true&type=js';
var newsContainer = document.createElement("div");
newsContainer.className = "newsContainer";
newsContainer.innerHTML = x;
document.getElementById("newsContainerId").appendChild(newsContainer);
This doesn't work however, as it appends this to the page
[object HTMLScriptElement]
Change newsContainer.innerHTML = x;
To
newsContainer.appendChild(x);
var x = document.createElement("SCRIPT");
x.src = '//rss.bloople.net/?url=https%3A%2F%2Fwww.coindesk.com%2Ffeed%2F&limit=5&showicon=true&type=js';
var newsContainer = document.createElement("div");
newsContainer.className = "newsContainer";
newsContainer.appendChild(x);
document.getElementById("newsContainerId").appendChild(newsContainer);
//
<div id="newsContainerId">Container</div>
The issue occurs here:
newsContainer.innerHTML = x;
xis evaluated - which you can't really do on this object. You should use x.innerHTML do make it do what you'd expect. Just x by itself is described by JavaScript as [object HTMLScriptElement] and that is what gets added to your newsContainer.
Try skipping this shoving around in the first place and add the element x to newscontainer:
var x = document.createElement("SCRIPT");
x.src = '//rss.bloople.net/?url=https%3A%2F%2Fwww.coindesk.com%2Ffeed%2F&limit=5&showicon=true&type=js';
var newsContainer = document.createElement("div");
newsContainer.className = "newsContainer";
newsContainer.appendChild(x);
document.getElementById("newsContainerId").appendChild(newsContainer);

HTML JavaScript delay downloading img src until node in DOM

Hi I have markup sent to me from a server and I set it as the innerHTML of a div element for the purpose of traversing the tree, finding image nodes, and changing their src values. Is there a way to prevent the original src value from being downloaded?
Here is what I am doing
function replaceImageSrcsInMarkup(markup) {
var div = document.createElement('div');
div.innerHTML = markup;
var images = div.getElementsByTagName('img');
images.forEach(replaceSrc);
return div.innerHTML;
}
The problem is that in browsers as soon as you do:
var img = document.createElement('img'); img.src = 'someurl.com' the browser fires off a request to someurl.com. Is there a way to prevent this without resorting to parsing the markup myself? If there is in no other way does anyone know a good way of parsing the markup with as little code as possible to accomplish my goal?
I know you are already happy with your solution, but I think it would be worth sharing a safe method for future users.
You can now simply use the DOMParser object to generate an external document from your HTML string, instead of using a div created by your current document as container.
DOMParser specifically avoids the pitfalls mentioned in the question and other threats: no img src download, no JavaScript execution, even in elements attributes.
So in your case you can safely do:
function replaceImageSrcsInMarkup(markup) {
var parser = new DOMParser(),
doc = parser.parseFromString(markup, "text/html");
// Manipulate `doc` as a regular document
var images = doc.getElementsByTagName('img');
for (var i = 0; i < images.length; i += 1) {
replaceSrc(images[i]);
}
return doc.body.innerHTML;
}
Demo: http://jsfiddle.net/94b7gyg9/1/
Note: with your current code, browsers will still try downloading the resource initially specified in your img nodes src attribute, even if you change it before the end of JS execution. Trace network transactions in this demo: http://jsfiddle.net/94b7gyg9/
Rather than append the new markup to the DOM before you change the img sources, create an element, set it's inner HTML, change the source of the images and then finally, append the changed markup to the page.
Here's a fully-worked sample.
<!DOCTYPE html>
<html>
<head>
<script>
"use strict";
function byId(id,parent){return (parent == undefined ? document : parent).getElementById(id);}
//function allByClass(className,parent){return (parent == undefined ? document : parent).getElementsByClassName(className);}
function allByTag(tagName,parent){return (parent == undefined ? document : parent).getElementsByTagName(tagName);}
function newEl(tag){return document.createElement(tag);}
//function newTxt(txt){return document.createTextNode(txt);}
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////
window.addEventListener('load', onDocLoaded, false);
function onDocLoaded()
{
byId('goBtn').addEventListener('click', onGoBtnClick, false);
}
var dummyString = "<img src='img/girl.png'/><img src='img/gfx07.jpg'/>";
function onGoBtnClick(evt)
{
var div = newEl('div');
div.innerHTML = dummyString;
var mImgs = allByTag('img', div);
for (var i=0, n=mImgs.length; i<n; i++)
{
mImgs[i].src = "img/murderface.jpg";
}
document.body.appendChild(div);
}
</script>
<style>
</style>
</head>
<body>
<button id='goBtn'>GO!</button>
</body>
</html>
You could directly parse the markup string using a regex to replace the img src. Searching for all the img src urls in the string and then replacing them with the new url.
var regex = /<img[^>]+src="?([^"\s]+)"?\s*\/>/g;
var imgUrls = [];
while ( m = regex.exec( markup ) ) {
imgUrls.push( m[1] );
}
imgUrls.forEach(function(url) {
markup = markup.replace(url,'new-url');
});
Another solution might be, if you have access to it, to set the all the img src to an empty string, and put the url in in a data-src attribute. Having your markup string look like something like this
markup = '
';
Then setting this markup to your div.innerHTML won't trigger any download from the browser. And you can still parse it using regular DOM selector.
div.innerHTML = markup;
var images = div.getElementsByTagName('img');
images.forEach(function(img){
var oldSrc = img.getAttribute('data-src');
img.setAttribute('src', 'new-url');
});

Javascript not running nearlyfreespeech

I set up an e-commerce website for a friend using javascript and html, and with the nearlyfreespeech hosting service. I have made sure to load the html page correctly, and there are no errors (in both the console and on the actual page). I have also tried with both the javascript embedded in the html, and with 2 seperate files, but neither works. I am using no external libraries either. I added alerts for when the page loads, but nothing showed up. The page constructor is hooked up to the page via the onload event set on the body tag. I have tried it with Firefox, Google Chrome, and Internet Explorer, but neither worked. When I moved the creation of the controls into the html, the controls were there (meaning that the html is working), but the alerts still didn't show (signifying that the javascript is either being omitted or that the onload event is not being fired). Here is the code:
<!DOCTYPE HTML>
<html>
<head>
<title>GetLost</title>
<script type="text/javascript">
function loadcontrols()
{
var items = ["Green cuff", "Red cuff"];
var prices = ["20.00", "30.00"];
var colors = ["Green", "Red"];
var urls = ["http://media-cache-ak0.pinimg.com/736x/0f/f8/11/0ff811addad9b0165263eb73ba9806f0.jpg", "http://www.opalona.com/images/produits/big/big_2049-3.jpg"];
var controls = [];
for(var i = 0; i < items.length; i++)
{
var item = new loaditem(items[i], prices[i], colors[i], urls[i]);
controls.concat(item);
}
alert("All items loaded.")
}
function loaditem(name, value, color, imageUrl)
{
this.name = name;
this.value = value;
this.color = color;
this.imageUrl = imageUrl;
var container = document.CreateElement("div");
container.style.height = "300px";
container.style.width = "200px";
container.style.backgroundColor = color;
scroller.appendChild(container);
var image = document.CreateElement("img");
image.style.height = "220px";
image.style.witdh = "180px";
image.setAttribute("src", imageUrl);
container.appendChild(image);
var name = document.CreateElement("h4");
name.innerHTML = name + " for $" + value;
container.appendChild(name);
alert("The product " + name + "has been loaded.")
}
</script>
</head>
<body onload="loadcontrols">
<h1><b>Choose a product, and click on it to open it.</b></h1>
<div style="overflow-x: scroll" name="scroller" height="310px" width="650px"></div>
</body>
</html>
onload doesn’t take a function name; it takes some JavaScript code to run. If you had a single line of JavaScript code just referencing a variable:
loadcontrols
Then, well, nothing happens. If you want to call it, you need parentheses:
loadcontrols()

Categories

Resources