Having trouble with createElement and appendChild - javascript

I have a reasonably simple idea that I would like to implement.
I have an array of objects with two properties: "id" and "name" I would like to list these in a series of "p" tags that would be within a "div".
So here is the HTML:
<body>
<div id="listView"></div>
</body>
And here is the JavaScript in the tag:
sessionStorage.eventid = 2;
var playerList = [];
playerList[0].id = 0;
playerList[0].name = "Add New Player";
playerList.push({
id: 5,
name: "Asako"
});
playerList.push({
id: 6,
name: "James"
});
playerList.push({
id: 7,
name: "Brian"
});
playerList.push({
id: 8,
name: "Helmut Spargle"
});
function listAll() {
var element = document.getElementById("listView");
var div;
var node;
for (var i = 0; i < playerList.length; i++) {
div = document.createElement("div");
div.setAttribute("onClick", "javascript: formOver(" + playerList[i].id + ")");
node = "<p>" + playerList[i].name + "<br />\n" +
"<small>&nbsp</small>\n" +
"</p>\n";
div.appendChild(node);
element.appendChild(div);
}
}
window.onLoad = function(){
listAll();
}
This doesn't fill the with anything. I have put this up on JSFiddle as well.
Have I misunderstood how Array.push works? Or something to do with appendChile and createElement?
Thanks in advance for your help.

Two problems - up front, trying to set the id and name on playerList[0] (which doesn't exist yet) won't work.
Second, trying to add a whole "node" full of html, jQuery-style, doesn't work in a plain-JS world. You need to build up the individual elements.
sessionStorage.eventid = 2;
var playerList = [];
playerList.push({
id: 0,
name: "Add New Player"
});
playerList.push({
id: 5,
name: "Asako"
});
playerList.push({
id: 6,
name: "James"
});
playerList.push({
id: 7,
name: "Brian"
});
playerList.push({
id: 8,
name: "Helmut Spargle"
});
function listAll() {
var element = document.getElementById("listView");
var div = document.createElement("div");
var node = "some string";
for (var i = 0; i < playerList.length; i++) {
div = document.createElement("div");
div.setAttribute("onClick", "formOver(" + playerList[i].id + ")");
var p = document.createElement('p');
p.innerHTML = playerList[i].name;
var br = document.createElement('br');
p.appendChild(br);
var small = document.createElement('small');
small.innerHTML = ' ';
p.appendChild(small);
div.appendChild(p);
element.appendChild(div);
}
}
listAll();
Example: http://jsfiddle.net/NF45y/

Initially:
var playerList = [];
playerList[0].id = 0;
You should get an error here about trying to set the id property of undefined. You can do:
var playerList = [{}];
playerList[0].id = 0;
playerList[0].name = "Add New Player";
or add the object the same way the others are. Within the function;
function listAll() {
var element = document.getElementById("listView");
var div;
var node;
for (var i = 0; i < playerList.length; i++) {
div = document.createElement("div");
div.setAttribute("onClick", "javascript: formOver(" + playerList[i].id + ")");
Don't use setAttribute to add listeners that way, it's not how it's intended to be used and doesn't work everywhere, use DOM properties for simplicity:
div.onclick = function(){...};
Since you are setting values inside a loop, you need to break the closure with the variables. An immediately invoked function expression (IIFE) can help:
div.onclick = (function(id) {
return function(){formOver(id);}
}(playerList[i].id));
Don't use XML syntax in an HTML document, and there isn't much point in the '\n' unless you are going to read the markup:
node = "<p>" + playerList[i].name + "<br><small>&nbsp</small></p>";
div.appendChild(node);
appendChild expects a DOM element, not markup. Since this is the only content of the div, you can use the markup to set its innerHTML property (you might want to change the name of node to say markup):
div.innerHTML = node;
element.appendChild(div);
}
}

Related

OnClick() event is not working in JavaScript for dynamic button in my code

I have added a dynamic buttons inside for loop on webpage using JavaScript and assigned a unique id to each button. I wants to assign onclick() event Listener to each button but this function is not being assigned to any of dynamic buttons. Kindly help me resolving this. Thank You.
myfunction()is working but myfunction1() has some problem. I cannot see onclick event in its dynamically HTML.
There are JS file. data.js contains arrays of objects and other contains function which access the data.
// function.js
function chargerArticles() {
var myShoppingCart = [];
var articles = document.getElementById("content");
for (var i = 0; i < catalogArray.length; i++) {
//Product div
var article = document.createElement("div");
article.setAttribute("class", "aa");
//Unique id
article.id = i + "-article";
//Product Name
var articleName = document.createElement("h4");
articleName.setAttribute("class", "aa-product-title");
var articleNameLink= document.createElement('a');
articleNameLink.setAttribute('href',"#");
articleNameLink.innerText = catalogArray[i].name;
articleName.appendChild(articleNameLink);
article.appendChild(articleName);
//Command Input Area
var zoneCmd = document.createElement("div");
var inputCmd = document.createElement("input");
//Button of add to cart
var button = document.createElement("BUTTON");
button.setAttribute("class", "Btn hvr-underline-btn");
button.innerHTML = " ADD";
//Button unique id
button.id = i + "-cmd";
//not working
button.addEventListener("click", myFunction1);
function myFunction1() {
var item = this.getAttribute("id");
var pos = item.substring(0, 1);
document.getElementById("1235").innerHTML = "Hello World";
addToCart(pos);
}
//working
document.getElementById("1234").addEventListener("click", myFunction);
function myFunction() {
document.getElementById("1234").innerHTML = "YOU CLICKED ME!";
}
zoneCmd.appendChild(button); //child 2
//zoneCmd child of article element
article.appendChild(zoneCmd);
//finally article as a child of articles
articles.appendChild(article);
}
}
function searchInCart(name) //T-Shirt
{
myShoppingCart = myCartArray;
var name1 = name;
var stop = 0;
for (var i = 0; i < myShoppingCart.length && stop == 0; i++) {
if (myShoppingCart[i].name == name1) {
stop = 1;
// console.log("Hello wooooorld!");
return true;
} else {
return false;
}
}
}
function addToCart(pos) {
if (searchInCart(catalogArray[pos].name)) {
alert("Already Exist!"); // display string message
} else {
var ident = pos + "-qte";
var quatity = document.getElementById("ident").value;
if (quatity > 0) {
var articleCmd = {}; //array of objects
articleCmd.name = catalogArray[pos].name;
articleCmd.price = catalogArray[pos].price;
articleCmd.qte = quatity;
articleCmd.priceTotal = articleCmd.price * articleCmd.qte;
myCartArray.push(articleCmd);
} else {
// alert
}
}
}
//data.js
// data.js
var catalogArray = [{
code: 100,
name: "T Shirt c100",
desc: "Lorem ipsum, or lipsum as it is sometimes known as",
price: 150,
image: "./images/img100.jpg"
},
{
code: 101,
name: "T Shirt c101",
desc: "Lorem ipsum, or lipsum as it is sometimes known as",
price: 250,
image: "./images/img101.jpg"
},
];
var myCartArray = [{
name: "T Shirt c100",
price: 150,
qte: 2,
TotalPrice: 150,
}
];
This issue occurred because you defined myfunction1 dynamically. In other words, this element wasn't defined during the initial rendering of the page.
You can fix it by using event delegation. Here is how:
Instead of defining the callback on the element, define it for all children of the PARENT element that have the matching css class. For example:
$( ".btnContainer .btn" ).on( "click", function( event ) {
event.preventDefault();
console.log("clicked");
});
where:
<div class='btnContainer'>
</div>
Now when you add buttons with (class name btn) dynamically as children of btnContainer, they will still get access to the click handler, because the event handler isn't bound to the element btn, but to it's parent, hence when the click event is fired, the parent delegates the event to all it's children with the matching class(es)!
Do not add a function in a loop
Delegate
Have a look here. There are MANY issues, I have addressed a few of them
You MAY want to do
button.setAttribute("data-code",item.code);
instead of
button.id = i + "-cmd";
// function.js
const content = document.getElementById("content");
content.addEventListener("click",function(e) {
const tgt = e.target, // the element clicked
id = tgt.id; // the ID of the element
if (id.indexOf("-cmd") !=-1) { // is that element one of our buttons?
// get the name of the article from the button - this could also be a data attibute
var pos = id.split("-")[1];
addToCart(pos);
}
})
function chargerArticles() {
const myShoppingCart = catalogArray.map(function(item, i) {
//Product div
var article = document.createElement("div");
article.setAttribute("class", "aa");
//Unique id
article.id = i + "-article";
// here would be a good place to add item.name or something
//Command Input Area
var zoneCmd = document.createElement("div");
var inputCmd = document.createElement("input");
//Button of add to cart
var button = document.createElement("BUTTON");
button.setAttribute("class", "Btn hvr-underline-btn");
button.innerHTML = " ADD";
//Button unique id
button.id = i + "-cmd";
zoneCmd.appendChild(button); //child 2
//zoneCmd child of article element
article.appendChild(zoneCmd);
//finally article as a child of articles
articles.appendChild(article);
content.appendChild(articles) // ???
})
}
function searchInCart(name) {
return myCartArray.filter(function(x) {
return x.name === name
})[0];
}

By iterating, dynamically set variables using strings from array

I got stuck. I need to create 4 new elements which will have the same class and different ID. The point is that I do not want to repeat a code... but my loop does not work.
I was trying to overcome this challenge for like 2 hours already (doing also a lot of research in Google), trying to find out what is going on using console.log and printing elements inside the iteration. Then, I needed to print console.dir to see attributes of created [object HTMLDivElement].
The code looks like this:
columnsArray = ["first", "second", "third", "fourth"]
for (var i = 0; i < columnsArray.length; i++ ) {
let name = columnsArray[i]
name = document.createElement("div");
name.className = "container"
name.setAttribute("id", name.name)
document.querySelector("#board" + boardId).appendChild(name);
}
I wonder if there is any relatively simple way (worth of trying) to achieve my aim? Except for this:
let first = document.createElement("div");
let second = document.createElement("div");
let third = document.createElement("div");
let fourth = document.createElement("div");
first.className = "container"
second.className = "container"
third.className = "container"
fourth.className = "container"
first.setAttribute = "first"
second.setAttribute = "second"
third.setAttribute = "third"
fourth.setAttribute = "fourth"
document.querySelector("#board" + boardId).appendChild(first);
document.querySelector("#board" + boardId).appendChild(second);
document.querySelector("#board" + boardId).appendChild(third);
document.querySelector("#board" + boardId).appendChild(fourth);
Thanks in advance for help;)
You're overriding the ID value from columnsArray in your loop by creating it as an element.
Create your element within a new variable:
columnsArray = ["first", "second", "third", "fourth"]
for (var i = 0; i < columnsArray.length; i++ ) {
// get the ID value from the array
let name = columnsArray[i];
// create a new element
let element = document.createElement("div");
// set its name
element.className = "container"
// set the ID value to columnsArray[i] (name)
element.setAttribute("id", name)
// append to board
document.querySelector("#board" + boardId).appendChild(element);
}
Your loop works fine, you just can't access the name in the way you think.
You have to set the id like this:
name.setAttribute("id", columnsArray[i])
name.name doesn't exist.
columnsArray = ["first", "second", "third", "fourth"];
boardId = 1;
for (var i = 0; i < columnsArray.length; i++ ) {
let name = document.createElement("div");
name.className = "container"
name.setAttribute("id", columnsArray[i]) // set name.id to columnsArray[i]
name.innerHTML = "DIV id="+columnsArray[i]
document.querySelector("#board" + boardId).appendChild(name);
console.log(name, name.id)
}
<div id="board1"></div>
Use name.setAttribute("id", columnsArray[i]) instead of name.setAttribute("id", name.name)
After that use
name.innerHTML = columnsArray[i]; //Replace it for some info or element
document.querySelector("#board" + boardId).appendChild(name);
use this:
columnsArray = ["first", "second", "third", "fourth"]
for (i in columnsArray) {
let name = columnsArray[i]
name = document.createElement("div");
name.className = "container"
name.setAttribute("id",columnsArray[i])
document.getElementById('boardId').appendChild(name);
}

HierarchyRequestError: Node cannot be inserted at the specified point in the hierarchy

var fieldArray = [];
var fields = {{ json_encode(Config::get('planner.'.$viewType.'_view_jobs')) }};
for(var i in fields) {
fieldArray.push([i, fields [i]]);
}
var outDiv = document.createElement('div');
for (var x = 0; x < fieldArray.length; x++) {
container[x] = document.createElement('div');
label[x] = document.createElement('div');
label[x].className = "label-job control-label";
$(label[x]).text(fieldArray[x][0]);
value[x] = document.createElement('div');
value[x].className = "label-value numeric";
eval("$(value[x]).text(event." + fieldArray[x][1] + ");");
container[x].appendChild(label[x]);
container[x].appendChild(value[x]);
}
outDiv.appendChild(container);
element.attr("data-toggle", "popover");
element.attr("data-content", $(outDiv).text());
element.append("<br />");
Hi All, this is my code. I am trying to append multiple 'label', 'value' into 'container'. Then append multiple 'container' into 'OutDiv'. However I got this error.
fieldArray = [["Ttl Job", "ttl_job"], ["Ctr Job", "ctr_job"]];
label, value, container is the var that store my createElementDiv
I really need your help. Thanks.

Javascript/html, dynamic divs, individual href's from 2d array?

I'm really new to javascript from C# and i'm having a little trouble. I wrote this function to make adding menu's a bit easier on my site. It works well except I can't seem to give my div's an individual url, even though I can give them an individual innerHtml.
I've been stuck trying different things such as divs[i].location.url etc.. but I can't seem to have anything work. My current solution has each div link to /contact.html which I'm a little confused by.
function DrawMainMenu() {
var btns = [
["About", "/about.html"],
["Portfolio", "/portfolio.html"],
["Resume", "/resume.html"],
["Contact", "/contact.html"]
];
var numOfBtns = btns.length;
var divs = new Array(numOfBtns);
for (var i = 0; i < numOfBtns; i++) {
divs[i] = document.createElement("div");
divs[i].className = "menuBtn";
divs[i].innerHTML = btns[i][0];
divs[i].style.height = (30 / numOfBtns) + "%";
divs[i].style.lineHeight = 3.5;
var link = btns[i][1];
divs[i].addEventListener('click', function() {
location.href = link;
}, false);
document.getElementById("buttons").appendChild(divs[i]);
}
}
Thanks
The problem is that the variable link gets overwritten each iteration, so when the event handler it gets link, which is the string '/contact.html', since that was the last value given to it.
You can try setting onclick attribute to elements, which will store the variable in the attribute onclick. Therefore, it will have the old and correct value.
function DrawMainMenu() {
var btns = [
["About", "/about.html"],
["Portfolio", "/portfolio.html"],
["Resume", "/resume.html"],
["Contact", "/contact.html"]
];
var numOfBtns = btns.length;
var divs = new Array(numOfBtns);
for (var i = 0; i < numOfBtns; i++) {
divs[i] = document.createElement("div");
divs[i].className = "menuBtn";
divs[i].innerHTML = btns[i][0];
divs[i].style.height = (30 / numOfBtns) + "%";
divs[i].style.lineHeight = 3.5;
var link = btns[i][1];
divs[i].setAttribute('onclick', 'location.href = "' + link + '"');
document.getElementById("buttons").appendChild(divs[i]);
}
}
DrawMainMenu();
<div id="buttons"><div>
Updated answer
Here we make use of closures. Using a closure (closing the values of link) we bind the value to the scope of the click handler.
function DrawMainMenu() {
var btns = [
["About", "/about.html"],
["Portfolio", "/portfolio.html"],
["Resume", "/resume.html"],
["Contact", "/contact.html"]
];
var numOfBtns = btns.length;
var divs = new Array(numOfBtns);
for (var i = 0; i < numOfBtns; i++) {
(function() {
divs[i] = document.createElement("div");
divs[i].className = "menuBtn";
divs[i].innerHTML = btns[i][0];
divs[i].style.height = (30 / numOfBtns) + "%";
divs[i].style.lineHeight = 3.5;
var link = btns[i][1];
document.getElementById("buttons").appendChild(divs[i]);
divs[i].addEventListener('click', function() {
location.href = link;
}, false);
}());
}
}
DrawMainMenu();
<div id="buttons"><div>

Pure JS | Basket | closure

I am working on a small JavaScript application that will users to click on buttons on the page and pass it through to thier basket. The problem I have with doing this is I am unsure as to handle multiple buttons within the same function. I do not want to have to write out different functions for each button.
I am trying to do it OOP and have this so far:
var shop = {};
shop.items = [];
shop.Item = function(item, description, price) {
this.item = item;
this.description = description;
this.price = price;
};
shop.print = function() {
var itemCon = document.getElementById('items'),
html = "";
for(var i = 0; i < this.items.length; i++) {
html += '<div id="item">';
for(prop in this.items[i]) {
html += '<p><span class="title">' + prop + '</span>: ' + this.items[i][prop] + '</p>';
};
html += '<button id="' + this.items[i].item + '">Add to Basket</button>'
html += '</div>';
};
itemCon.innerHTML += html;
};
shop.items[shop.items.length] = new shop.Item("Coat", "Warm", "20");
shop.items[shop.items.length] = new shop.Item("Coat", "Warm", "20");
shop.items[shop.items.length] = new shop.Item("Coat", "Warm", "20");
shop.items[shop.items.length] = new shop.Item("Coat", "Warm", "20");
var basket = {};
basket.items = [];
basket.Item = function(item, description, price) {
this.item = item;
this.description = description;
this.price = price;
};
basket.add = function(data) {
this.items[items.length] = new Item(data.item, data.description, data.price);
};
basket.costCalculate = function() {
var cost = 0,
html = "Total: " + cost;
for(var i = 0; i < this.items.length; i++) {
cost += items[i].price;
};
return html;
};
basket.print = function() {
var output;
for(var i = 0; i < this.items.length; i++) {
for(prop in this.items[i]) {
console.log(prop + ": " + this.items[i][prop]);
};
};
};
function init() {
shop.print()
};
window.onload = init;
How would I determine what item has been clicked in order to run basket.add(data). How would I also pass through the data to that function for each item.
Also how would one go about implementing closure? I understand that it is inner functions having access to the variables of the outer functions, is what I am doing working with closure so far?
Okay, you've made a pretty good start but here are a couple suggestions:
It's probably a good idea to only have one instance of each Item. By that I mean it looks like you create a bunch of Items for to populate your shop's inventory, so for example:
var coat = new Item("Coat", "Warm", 20);
shop.items.push(coat);
Now when you click on your UI element, you ideally want this same instance of coat to go into your basket as well, so:
// User clicks on UI element, which triggers the following to execute:
basket.add( someItemIdentifier );
So now if you ever decide to increase all your prices by $10, you can simply do:
shop.increasePricesBy = function(amount) {
for(var i = 0; i < shop.items.length; i++) {
shop.items[i].price += amount;
}
// execute some function to update existing baskets' totals
};
I hope this makes sense for why there should be one instance of each item that multiple collections refer to.
This begs the question how you can tie the customer's interaction to adding the correct item. One solution could be to use arbitrary IDs to track items. For example:
// Create new item with some randomly generated ID
var coat = new Item({
id: "93523452-34523452",
name: "Coat",
description: "Warm",
price: 20
});
shop.items = {}; // Use a hash so it's easier to find items
shop.items[coat.id] = coat;
And your UI element could be some div like so:
<div class="add-product-button" data-id="93523452-34523452">
Add your click handler:
// Pure JS solution - untested
var clickTargets = document.getElementsByClassName("add-product-button");
for(var i = 0; i < clickTargets.length; i++) {
var clickTarget = clickTargets[i];
clickTarget.onClick = function() {
var itemID = clickTarget.getAttribute("data-id");
var item = shop.items[itemID];
basket.add(item);
};
}
// Equivalent jQuery code
$(".add-product-button").click(function() {
var id = $(this).attr('data-id');
var item = shop.items[id];
basket.add(item);
});
While your basket implements add something like:
basket.add = function(items) {
this.items.push(item);
};
And your costCalculate method gets a whole lot easier:
basket.costCalculate = function() {
var cost = 0;
for(var i = 0; i < this.items.length; i++) {
cost += this.item[i].price;
}
return cost;
};
Instead of doing this:
shop.items[shop.items.length] = new shop.Item("Coat", "Warm", "20");
You can instead do:
shop.items.push(new shop.Item("Coat", "Warm", "20");
Probably a good idea to use a number instead of a string to represent the price.
In your shop.print loop, you probably don't want to hard code <div id="item"> because that will result in multiple divs with the same id.
Finally, I'm not going to try to answer your closure question here because I think that's been answered better than I can already so I'll just link you to some great resources that helped me understand it:
Best stackoverflow thread on how JS Closures work
MDN's doc on closures
Javascript: The Good Parts by Douglas Crockford. It's a tiny book, and talks about some great concepts - especially working with Prototypes which I suspect you'd find useful to help you with this project.
Let me know if you have any questions, I'm totally down to discuss them.

Categories