1. Advertising
    y u no do it?

    Advertising (learn more)

    Advertise virtually anything here, with CPM banner ads, CPM email ads and CPC contextual links. You can target relevant areas of the site and show ads based on geographical location of the user if you wish.

    Starts at just $1 per CPM or $0.10 per CPC.

Adding a .js in my html.

Discussion in 'HTML & Website Design' started by SSORE7, Dec 3, 2015.

  1. #1
    Hi, I made a .js file and I've added in my html body and it runs. It's that.

    
    
    var lunch = prompt("What do you want for lunch?","Type your lunch choice here");
    
    switch(lunch){
      case 'sandwich':
        console.log("Sure thing! One sandwich, coming up.");
        break;
      case 'soup':
        console.log("Got it! Tomato's my favorite.");
        break;
      case 'salad':
        console.log("Sounds good! How about a caesar salad?");
        break;
      case 'pie':
        console.log("Pie's not a meal!");
        break;
      default:
        console.log("Huh! I'm not sure what " + lunch + " is. How does a sandwich sound?");
    }
    Code (JavaScript):
    I want to make the string between console.log to run on the page like a paragraph. The code ask me the question but never answer back after my imput.
     
    SSORE7, Dec 3, 2015 IP
  2. sarahk

    sarahk iTamer Staff

    Messages:
    28,500
    Likes Received:
    4,460
    Best Answers:
    123
    Trophy Points:
    665
  3. deathshadow

    deathshadow Acclaimed Member

    Messages:
    9,732
    Likes Received:
    1,998
    Best Answers:
    253
    Trophy Points:
    515
    #3
    It shows up in the console, but that's NOT what they are asking... I think.

    I believe they are asking how to get it to show on the page like it was in the markup.

    there are three approaches, only one of them is actually worth using.

    The simplest is to use document.write instead of console.log. The problem with this approach is that if the page isn't finished loading it will hang the render making the page take longer to load -- and if the page is done loading it will erase everything on the page.

    The next method is the innerHTML property, you need to have an element on the page you want to plug the content into, and you just do Element.innerHTML = "Your string here"; -- the problem is this forces a reflow of the page that can result in triggering unwanted behaviors and wasting battery on mobile devices. It will seem faster if you measure it "raw" in the scripting than the next method, but that's NOT the only place it has a speed impact. We've been told for 15 years by the ECMA not to use innerHTML, Joe forbid we listen to them!

    The final technique involves manipulating the DOM -- document object model. You create a new textNode and append it to an existing HTML element, or even create an element to put it in and then append that element to BODY or some other part of the page.

    So, let's say you had this in your HTML:

    <p id="result"></p>

    To plug in your values to that the scripting would look like this:
    var
    	lunch = prompt("What do you want for lunch?","Type your lunch choice here"),
    	target = document.getElementById('result');
    	
    switch (lunch) {
    	case 'sandwich':
    		target.appendChild(document.createTextNode(
    			"Sure thing! One sandwich, coming up."
    		));
    		break;
    	case 'soup':
    		target.appendChild(document.createTextNode(
    			"Got it! Tomato's my favorite."
    		));
    		break;
    	case 'salad':
    		target.appendChild(document.createTextNode(
    			"Sounds good! How about a caesar salad?"
    		));
    		break;
    	case 'pie':
    		target.appendChild(document.createTextNode(
    			"Pie's not a meal!"
    		));
    		break;
    	default:
    		target.appendChild(document.createTextNode(
    			"Huh! I'm not sure what " + lunch + " is. How does a sandwich sound?"
    		));
    }
    Code (markup):
    That will plug the text into that paragraph using the dom. You could replace all those "target.appendChild(document.createTextNode" with "target.innerHTML=", but that can be slower and have undesired side effects like doing a full reparse of the entire document.

    A LOT of people will tell you to just use innerHTML -- mouthbreathing halfwit bullshit like jQuery will teach you similar bloated/broken methodologies -- JUST SAY NO!
     
    deathshadow, Dec 3, 2015 IP
    kk5st likes this.
  4. kk5st

    kk5st Prominent Member

    Messages:
    3,497
    Likes Received:
    376
    Best Answers:
    29
    Trophy Points:
    335
    #4
    @deathshadow
    Nice breakdown on the methods. I don't think I've used document.write more than a few times, ever. innerHTML was never on my do-it-this-way list, though I tried it. Wasn't that an IE extension to the language? I recall there were compatibility issues for a while, or maybe I'm completely misremembering. DOM manipulation became my favorite early on, though IE had a lot of issues. I haven't done anything beyond trivial programming since retiring, so apply salt liberally.

    gary
     
    kk5st, Dec 4, 2015 IP
  5. ketting00

    ketting00 Well-Known Member

    Messages:
    772
    Likes Received:
    27
    Best Answers:
    3
    Trophy Points:
    128
    #5
    Hey, interesting.
    Is this the best practice?
    I use:
    
    element.firstChild.nodeValue = "What do you want for lunch?";
    Code (markup):
    Some posts on the internet say it is better than innerHTML but sometimes it doesn't work.
    Is mine bad too?
     
    ketting00, Dec 6, 2015 IP
  6. deathshadow

    deathshadow Acclaimed Member

    Messages:
    9,732
    Likes Received:
    1,998
    Best Answers:
    253
    Trophy Points:
    515
    #6
    @ketting00

    nodeValue is somewhat the same as innerHTML but not quite as it shouldn't require a reflow -- if/when it fails would be because you don't know the node-type of that firstChild. It could be a comment node, a textNode, an Element, in some browsers whitespace is tracked as nodeElements... So you really don't know what you're plugging that into. It also would NOT change/empty out the element if there's more than one node. If your element was pointing at this div:

    <div><span>This is the first Child</span><span>This would remain unchanged</span></div>

    Have a look at all the different nodeTypes:
    https://developer.mozilla.org/en-US/docs/Web/API/Node/nodeType#Node_type_constants

    not all nodes have a "nodeValue" and some that do that value is not displayed as content. Worse, that will throw an error if there are no children... so if you ran that on:

    <div></div>

    Say hello to an error condition as there is no firstChild of that DIV.

    The overhead of checking for all the possible cornercases would likely made nodeValue very hard to deploy and extremely prone to breaking. It's just too fragile and makes too many assumptions.

    Hence why I have a small set of handy "node" helper functions I call on a lot.

    function nodeFlush(e) {
    	while (e.firstChild) e.removeChild(e.firstChild);
    }
    
    function nodeAppend(e, newNode) {
    	return e.appendChild(
    		typeof newNode == "object" ? newNode : document.createTextNode(newNode)
    	);
    }
    
    function nodeInsert(e, newNode) {
    	return e.insertBefore(
    		typeof newNode == "object" ? newNode : document.createTextNode(newNode),
    		e.firstChild
    	);
    }
    
    function nodeReplace(e, newNode) {
    	nodeFlush(e);
    	return nodeAppend(e, newNode);
    }
    
    /*
    	Recursive call for nodeWalk can blow up the stack resulting in a fatal
    	error if you nest REALLY deep, so just don't nest elements more than 500
    	deep! Honestly if you're HTML has that many tags inside tags inside tags,
    	there's something terrifyingly wrong!
    */
    
    function nodeWalk(e, callback) {
    	e = e.firstChild;
    	while (e) {
    		callback(e);
    		if (e.firstChild) nodeWalk(e, callback);
    		e = e.nextSibling;
    	}
    }
    Code (markup):
    The little typeof check allows me to pass elements or plaintext and it will auto-handle the creation as/when needed. While a hair slower on the JS side, they are reliable and bypass the parser resulting in overall being faster. This approach also has the bonus of working all the way back to IE 5.5 Winblows and 5.2 Quackintosh.

    NodeWalk is cute, it's basically a foreach of all children and grandchildren of a DOM element. Laughably the browser most likely to bomb from too many nested elements on that recursive call is... Safari 3.x which only has enough of a call stack for around 500 recursions. Safari 4/newer upped that to around 32K. Even legacy IE doesn't bomb until around 1K of them... and really if you have tags nested that deep, there REALLY is something wrong.

    Laughably on a normal website, that nodewalk runs faster than it takes for getElementsByTagName('*') takes if you point it at BODY. For example:
    function testLog(e) {
    	if (e.nodeType == 1) console.log(e.tagName);
    }
    
    // slow method
    var eList = document.body.getElementsByTagName('*');
    for (var i = 0, lenE = eList.length; i < lenE; i++) testLog(eList[i]);
    
    // faster
    nodeWalk(document.body, testLog);
    Code (markup):
    Damned if I know why... but as a rule the "getElements" functions across the board aren't exactly the peppiest of routines. Probably why jQuery tries to cache it's "querySelector style" results in an object, which laughably just wastes memory and ends up a wash on speed in everything except Chrome thanks to how agonizingly slow object and array lookups are in most JS engines.

    ... and part of why Google V8 is so blasted fast; they fixed stupid things like that which really shouldn't be any slower than normal variable lookups.

    Node manipulation -- can be some real fun stuff. I actually started looking at DOM walking back in the day to try and make a faster polyfill for getElementsByClassName.

    In Soviet Russia, the DOM walks you.
     
    Last edited: Dec 6, 2015
    deathshadow, Dec 6, 2015 IP
  7. ketting00

    ketting00 Well-Known Member

    Messages:
    772
    Likes Received:
    27
    Best Answers:
    3
    Trophy Points:
    128
    #7
    Thanks @deathshadow for sharing and explanation.

    Your codes look awesome. Maybe one of the best I've seen so far. I'll use it when I have to manipulate the DOM. Sounds like some kind of fun.

    Oh, I really like your sloppy humor on Winblows and Quackintosh. /* Lamo */
     
    ketting00, Dec 6, 2015 IP
  8. deathshadow

    deathshadow Acclaimed Member

    Messages:
    9,732
    Likes Received:
    1,998
    Best Answers:
    253
    Trophy Points:
    515
    #8
    Oh, just occurred to me to mention a THIRD way of adding things, mixing createElement and innerHTML.

    One of the problems with innerHTML is it triggers a reflow of whatever element it is on. This can result in some browsers "flashing a white screen" while the chnages are applied, it can result in other browsers triggering onload when they shouldn't, and in general it can use a lot of CPU power to reparse the entire document.

    Solution if you "really" need to use innerHTML -- a great example of when it makes more sense is with a AJAX response -- is to mix dom manipulation and innerHTML.

    You see, if you apply innerHTML to an Element NOT attached to the DOM, the parser is called but only parses that one element, not the entire page!

    So if you wanted to for example add to the end of document.body a brand spanky new DIV with innerHTML inside it...

    var  e = document.createElement('div');
    e.id = 'testing';
    e.innerHTML = '<h2>Test Area</h2><p>This is a scripting test</p>';
    document.body.appendChild(e);
    Code (markup):
    It's not AS clean as using the DOM, but that innerHTML gets run on the DIV before it's added to the DOM. So if you feel you "have" to do it, or it is just more expedient to do so, that's the best way of resorting to using it.

    If you already have a DIV with that ID, you can pull a cute trick to replace it with the new one.

    var
    	oldNode = document.getElementById('testing'),
    	newNode = document.createElement('div');
    newNode.id = 'testing';
    newNode.innerHTML = '<h2>Test Area</h2><p>This is a scripting test</p>';
    oldNode.parentNode.replaceChild(newNode, oldNode);
    Code (markup):
    Will swap out the old DIV#testing for a new DIV#testing destroying the old one. It is also one of the few cases where it's ok to have two elements assigned the same ID as they never exist on the DOM at the same time!

    This too works all the way back to IE 5.

    There is... one other approach. If ALL you are replacing is text, or if you want to read JUST the text inside an element, there's "innerContent" and the non-standard "innerText".

    innerText despite being non-standard WILL SOON BE supported in all major browsers. Given the differences between it and innerContent I suggest a LOT of reading and contemplation before using either. The MDN pages are as always some of the better explanations:

    https://developer.mozilla.org/en-US/docs/Web/API/Node/textContent

    https://developer.mozilla.org/en-US/docs/Web/API/Node/innerText

    I really think the W3C and ECMA should just suck it up and make innerText the norm now that even Mozilla has up and decided "fine, we'll support it"... Like a lot of things that originated with Microsoft though, they have to make it "just different enough" from what the "evil empire" did with their dirty hippy rah-rah fight the man attitude.
     
    deathshadow, Dec 6, 2015 IP
    ketting00 likes this.