Nesting dynamic links into a dynamic list with Javascript - javascript

I have tried to create a function that creates a dynamic menu. Ive been able to create the "a" tags and give them individual links while also assigning them ID's. The problem is that I cant get the links inside of a list where my CSS applies its rules.
function write_navBar() {
var links = ["intro.html", "art.html", "portfolio.html", "guides.html", "about_me.html"]
var ul = document.createElement("ul");
document.getElementById("mainNav").appendChild(ul);
for (i = 0 ; i < links.length ; i++) {
var ul = document.createElement("ul");
var a = document.createElement("a");
var text = document.createTextNode(links[i]);
a.href = links[i];
a.id = "mainNav";
a.text = links[i];
document.getElementById("mainNav").appendChild(a);
}
}
Any suggestions on cleaning the code while keeping to javascript would be appreciated. And also any explanation of syntax would be also appreciated.
Thank you!

function write_navBar() {
var links = ["intro.html", "art.html", "portfolio.html", "guides.html", "about_me.html"];
var ul = document.createElement("ul");
var li, a, text;
for (var i = 0, l = links.length; i < l; ++i) {
li = document.createElement('li');
a = document.createElement('a');
text = document.createTextNode(links[i]);
a.href = links[i];
a.setAttribute("class", "some-class-name");
a.appendChild(text);
li.appendChild(a);
ul.appendChild(li);
}
document.querySelector("#mainNav").appendChild(ul);
}
• Use querySelector over getElementById. Both work, but theres a performance boost to querySelector. The API is close to jQuery and most (if not all) newer browsers support querySelector.
• Append the ul AFTER you've added the elements again for performance reasons.
• Use an LI to hold the link element, a second UL wont do what you want.
• Don't resuse id's, the thing you would want to use is a class, they basically do the same thing but javascript treats id's and classes differently. If that doesnt fit your needs, try a compound CSS selector in your css such as:
#mainNav ul li a { /* styles here */ }

You have to ensure that you append the correct items to the correct parents. Scanning your code I assume you want the following HTML output:
<div id="mainNav"> // this is already there
<ul>
<li>
intro.html
</li>
... // repeat for other items in the array
</ul>
</div>
You can modify your code like this to get the above result:
function write_navBar() {
var links = ["intro.html", "art.html", "portfolio.html", "guides.html", "about_me.html"]
var ul = document.createElement("ul");
document.getElementById("mainNav").appendChild(ul);
for (i = 0 ; i < links.length ; i++) {
var li = document.createElement("li");
var a = document.createElement("a");
a.href = links[i];
a.className = "some-class-to-target-in-your-css";
a.innerText = links[i];
ul.appendChild(li);
li.appendChild(a);
}
}

Your approach isn't that bad. I at one time took a similar outlook towards doing these. However, I am now of the belief it is far more testable, reliable, and easier to build these as actual templates, clone them, and populate them through a factory pattern.
In your setup, you have a parent ul, and then build multiple ul's with a's in them -- I am going to assume you meant to nest li elements -- and so that is what this will do.
Here is how I would approach that in your scenario.
Step 1: Build a the template, and create the styling and visual effect.
.navLink a{
padding:3px;
}
<ul class="menuTemplate">
<li class="navLink"><a></a></li>
</ul>
Simple style, I know. But it is just for simplicity, you can really do whatever you want there to style the example. Note that it is a simple structure, so all you are really seeing in there is a template, an li element, and the a element.
What we are also going to add to the style definition in our use case is
.menuTemplate{
display:none;
}
Because we don't actually want to see the template, we just want to use it. Next, we will create a factory for these.
var navFactory = new function(){
var template = document.querySelector('.menuTemplate .navLink');
this.Create = function(text,href){
var nav = template.cloneNode(true);
var link = nav.querySelector('a');
link.href = href;
link.innerText = text;
return nav;
}
};
The last step is to simply take your element that will hold the nav elements - you named this "mainNav" above - and fill it in from the factory.
var navFactory = new function(){
var template = document.querySelector('.menuTemplate .navLink');
this.Create = function(text,href){
var nav = template.cloneNode(true);
var link = nav.querySelector('a');
link.href = href;
link.innerText = text;
return nav;
}
};
function write_navBar() {
var links = ["intro.html", "art.html", "portfolio.html", "guides.html", "about_me.html"];
var navUl = document.querySelector('#mainNav ul');
for(var i = 0; i < links.length; i++){
navUl.appendChild(navFactory.Create(links[i],links[i]));
}
}
write_navBar();
.menuTemplate{
display:none;
}
.navLink a{
padding:3px;
opacity:0.85
}
.navLink a:hover{
opacity:1;
}
<ul class="menuTemplate">
<li class="navLink"><a></a></li>
</ul>
<div id="mainNav">
<ul></ul>
</div>

Related

Displaying an array in a UL using javascript

I need some help displaying my javascript array within a UL html element.
I have been trying to figure this out for the last 4 days and I am not getting it right.
See my code below:
function load() {
let favLanguages = ["html", "css", "javascript", "go", "ruby"];
// create ul element and set its attributes.
let ul = document.createElement("ul");
for (i = 0; i <= favLanguages.length; i++);
{
let li = document.createElement("li"); // create li element.
li.innerHTML = favLanguages[i]; // assigning text to li using array value.
document.getElementById(1);
ul.appendChild(li); // append li to ul.
}
}
html
<body onload="load()">
<h1>My favourite languages:</h1>
<ul id="1"></ul>
I would really appreciate any help
Thanks
You're pretty much there. You had a couple of issues:
You already have specified a ul element within your HTML. You don't need to re-create it again by doing document.createElement('ul'), just select the ul instead
You had your ul element's id as the number 1. When you tried to select the ul by doing document.getElementById(1)`, that will not work. You need to pass in the string of the id. I rename it to 'one' to fix it.
In your for(...) loop, you had a semi colon (;) after for(...);. That will not work. I removed the semi colon for you.
You last line of code ul.appendChild(li) is the only thing you need to do after you set your innerHTML. You already have the ul in the dom, so just append your new elements to that.
Example:
function load() {
const favLanguages = ["html", "css", "javascript", "go", "ruby"];
// Get a refrerence to the UL
const ul = document.getElementById('one');
for (i = 0; i <= favLanguages.length; i++) {
const li = document.createElement("li"); // create li element.
li.innerHTML = favLanguages[i]; // assigning text to li using array value.
ul.appendChild(li); // append li to ul.
}
}
load();
<h1>My favourite languages:</h1>
<ul id="one"></ul>
The second line has an inline comment disrupting the code on that line. So, the let ul = document.createElement("ul"); is not read by the JS engine. It can be fixed by moving the comment after the code.
Your for loop and your function declaration have a semicolon terminating it. Try fixing it like below:
function load() {
let favLanguages = ["html", "css", "javascript", "go", "ruby"]
let ul = document.createElement("ul"); // create ul element and set its attributes.
for (i = 0; i <= favLanguages.length; i++) { let li = document.createElement("li"); // create li element.
li.innerHTML = favLanguages[i]; // assigning text to li using array value.
document.getElementById(1);
ul.appendChild(li); // append li to ul.
}
}
window.onload = function(){
// init arr
let favLanguages = ["html", "css", "javascript", "go", "ruby"];
// get ul element after document loaded: window.onload
let ulNode = document.getElementById("a1");
// create ul element and set its attributes.
let ul = document.createElement("ul");
for (let i = 0; i < favLanguages.length; i++){
let li = document.createElement("li"); // create li element.
li.innerText = favLanguages[i]; //inrHTML if you have new element
ulNode.appendChild(li);
}
}
<h1>My favourite languages:</h1>
<ul id="a1"></ul>

access to div element

i have created a webside, there I have a div element with the id "buttons".
Below you see how i create buttons with the alphabet on them. Everything fine and it works.
But now I have to get access to only one button/one letter of the 26 buttons.. so that I can change the opacity of one button. (i just can handle it that all of them get more transparent!)
maybe somebody can help me -thanks!
var buttons = function () {
myButtons = document.getElementById("buttons");
letters = document.createElement('ul');
for (var i = 0; i < alphabet.length; i++) {
letters.id = 'alphabet';
list = document.createElement('li');
list.id = 'letter';
list.innerHTML = alphabet[i];
check();
myButtons.appendChild(letters);
letters.appendChild(list);
}
}
You can set the id of your list elements with list.id='letter' + i.
Then you can access each button with document.getElementById('letter<i>') - for the first one document.getElementById('letter0') and so on.
You should move letters.id = 'alphabet'; outside of your for-loop because you don't have to set the id in every loop.
I updated your codes, You can just see the example.
Example:
var alphabet = "ABCDEFGHIJKLMNOPQRSTUVWXYZ"; /*Just Defined for this snipped test*/
var buttons = function (ID) {
var ul = document.createElement('ul');
ul.id = 'alphabet';
for (var i = 0; i < alphabet.length; i++) {
li = document.createElement('li');
li.id = 'letter'+i; /*id="letter0",id="letter1",...*/
li.innerHTML = alphabet[i];
/*check();*/
ul.appendChild(li);
}
ID.appendChild(ul);
}
var myButtons = document.getElementById("buttons");
buttons(myButtons); /*Called the function and pass the Object for append*/
<div id="buttons"></div>
Generated HTML code from above snippet:
<div id="buttons">
<ul id="alphabet">
<li id="letter0">A</li>
<li id="letter1">B</li>
<li id="letter2">C</li>
.......................
<li id="letter25">Z</li>
</ul>
</div>
So, you can use different CSS for every ID's. Or you can change CSS from button() function by updating your code.
You may NOT use same ID to different elements (You had created more then one element and gave it same ID).
Here another method to solve the problem you had shown. (without using "id" field), Just because you already have very good answers using the "id" property properly.
<!doctype html>
<html>
<head>
<title>
Test
</title>
<script type='text/javascript'>
'use strict';
var m_Buttons = [];
function Init() {
var myButtons = document.getElementById("buttons");
var alphabet = ['a','b','c','d','e','f','g']; //go on with letters yourself
var ul = document.createElement('ul');
var li = null;
for (var i=0; i<alphabet.length; i++) {
li = document.createElement('li');
li.innerHTML = alphabet[i];
ul.appendChild(li);
m_Buttons.push (li);
}
myButtons.appendChild(ul);
}
function getButton(button_index) {
m_Buttons[button_index].style.color = 'red';
return Buttons[button_index];
}
</script>
</head>
<body onload='Init();'>
<div id='buttons'>
</div>
<button onclick='getButton(3);'> Click to get button 3 </button>
</body>
</html>

DOM Manipulation

Newbie question - Is this code eloquent enough to create four list items? or Should I be using documentFragment instead? The code seems to work fine - JsFiddle.
Created list and li variables
var list = document.getElementById("myList");
var li = null;
Created x number of list elements and companion text nodes
for(var i=1; i<=4; i++){
var li = document.createElement("li");
li.appendChild(document.createTextNode("Number " + i));
Add li to list
list.appendChild(li);
}
Based entirely on the JSFiddle demo you've provided: No. What you currently have is semantically incorrect. You're currently appending your li to the body, not the ul element:
<ul></ul>
<li>Number 1</li>
Change:
document.body.appendChild(li);
To:
list.appendChild(li);
JSFiddle demo.
As for the code you've provided in the question, you also need to change it so that your li elements get appended to your ul element. You also need to change your class into an ID, as getElementById("myList") pulls an element with an ID of "myList", whereas your current ul has no such ID.
Actually there is an error, because you're adding the lis to the body instead of the ul
also the markup is not well created, change
<ul class="myList"></ul>
with
<ul id="myList"></ul>
To use an id and then:
var list = document.getElementById("myList");
var li = null;
for(var i=1; i<=4; i++){
var li = document.createElement("li");
li.appendChild(document.createTextNode("Number " + i));
//document.body.appendChild(li); **error here**
list.appendChild(li); //fix
}

document fragments and appending children

I'm new to the concept of document fragments and I am currently having some trouble figuring out how to append children to a fragment.
This is my html
<form>
<ul id="tweets">
<li><img src="tweetIcon.jpg"><span>This is my tweet</span></li>
</ul>
</form>
Below is my script:
var tweets = [
"When teaching math, it shouldn't just be: 'Answer this question:'. It should also be: 'Question this answer:'",
"Another reason to choose ",
" Excellent! I love the new APIs that came with it, as well as the new tags and attributes.",
"That's great. I am really grateful for your program and will definitely continue to encourage folks to enroll in courses!"
];
function init() {
var ul = document.getElementById("tweets");
var fragment = document.createDocumentFragment();
for (var i = 0; i < tweets.length; i++) {
var tweet = tweets[i];
var li = document.createElement("li");
var span = document.createElement("span");
span.innerHTML = tweet;
var img = document.createElement("img");
img.setAttribute("src", "tweetIcon.jpg");
li.appendChild(span);
ul.appendChild(li);
fragment.appendChild(img);
fragment.appendChild(li);
}
ul.appendChild(fragment);
}
Right now I see the img and the span element only once at the top of the list. Below are all the strings for the tweets correctly displayed as a list. I need to add the image and the span element to each tweet. The three lines that are commented out are where I attempted to add the image to each li element as a child, but those lines don't really do anything. Any suggestions? thanks!
Move the document.createElement("img") inside the loop, otherwise you're repeatedly moving and changing the same image object.

JavaScript: how to get img and div elements using getElementsByTagName

I have a tree structure as follows:
<ul id="theul275">
<li>
<div id="red"></div>
<img id="green" />
<script></script>
<div id="blue"></div>
</li>
</ul>
There are multiple UL's likes this on my page each with a different id. I am getting each UL by doing this:
var child = document.getElementById('theul' + id).getElementsByTagName('*');
the problem is, I only want to get the children of each ul which are either div's or img's.
Is there a way to get elements by multiple tag names?
I really appreciate any help because I am kind of new to JavaScript! Thanks!
Depending on what browsers you may to support, you could use the CSS selector interface.
document.getElementById('theul275').querySelectorAll('div, img');
Or use a library. There are plenty of options out there. I am familiar with two,
MooTools
$('theul275').getElements('div, img');
jQuery
$('#theul275').find('div, img');
Or get a reference to the li node, and loop through each node and check if the nodeName is DIV or IMG.
for (var i = 0, l = child.length; i < l; i++)
{
if (child[i].nodeName == 'DIV' || child[i].nodeName == 'IMG')
{
//...
}
}
You could use a iterative method for this.
var elemArray = document.getElementById('theul' + id).childNodes,
getChildByNodeName = function (elem, pattern) {
var childCollection = [],
re = new RegExp(pattern, 'g'),
getChild = function (elements) {
var childs = elements.childNodes,
i = 0;
if (childs) {
getChild(childs);
for (i = 0; i < childs.length; i += 1) {
if (childs[i].nodeName.match(pattern)) {
childCollection.push(childs[i]);
}
}
}
};
getChild(elem);
return childCollection;
}
var childs2 = getChildByNodeName(elemArray, '^(DIV|IMG)$'); // array of match elements
And just change the pattern ('^(DIV|IMG)$') to suite your needs.
If you can use jQuery, try
var child = $("#theul" + id).find("div,img");
Otherwise, see JavaScript NodeList.

Categories

Resources