I'm working on an Ionic-app.
On one of my pages i'm adding elements dynamically to a div-element.
The elements are added but i can't see them on the page.
Just after clicking F5 and running the controller-code again i can see them.
Here's the code for adding the elements:
if ($scope.eigenschaften != null) {
//TODO Eigenschaften in Loop durchgehen und auf panel_dynamic Controls erzeugen
var panel_dynamic = document.getElementById('panel_dynamic');
if (panel_dynamic.hasChildNodes()) {
panel_dynamic.removeChild(panel_dynamic.childNodes[0]);
}
var content = document.createElement('div');
for (n = 0; n <= $scope.eigenschaften.length - 1; n++) {
// Creates a new div with controls
var line = document.createElement('div');
var para = document.createElement('p');
// Creates a div-row
var div_row = document.createElement('div');
div_row.setAttribute('class', 'row');
// Creates a div-col with label
var div_col_label = document.createElement('div');
div_col_label.setAttribute('class', 'col');
div_col_label.appendChild(CreateLabel('font-size:16px;font-weight:bold;', $scope.eigenschaften[n].name));
div_row.appendChild(div_col_label);
// Creates a div-col with control
var div_col_control = document.createElement('div');
div_col_control.setAttribute('class', 'col');
div_col_control.appendChild(CreateTextbox());
div_row.appendChild(div_col_control);
// Adds the div-row to the para
para.appendChild(div_row);
// Adds the new para to the line
line.appendChild(para);
// Adds the new line to the content
content.appendChild(line);
}
// Adds the content-div to panel_dynamic
panel_dynamic.appendChild(content);
}
"eigenschaften" is an array with the data.
It looks like you aren't triggering change detection. You should add the elements using an ng-repeat in your template that's bound to an array or some other iterable on the model instead. Then everytime you add something new to the iterable, it will get added in the view.
Unfortunately i used the id for my container-div "panel_dynamic" even in another template. And JavaScript was getting the other div by getElementById. Now i have changed the ids and it works.
Related
The code below makes a Div for every object it finds in an array. It then adds a header, a paragraph, an image, and an anchor.
The div's actually look like rectangles on top of one another. What I would like to do is add an onclick attribute to the divs based on the keys within my objects ( coffeShops[i].menu). When I do so though, clicking just doesn't do anything and i get this error message in console
"Uncaught TypeError: Cannot read property 'menu' of undefined"
This only happens when I try window.open with the object key coffeShops[i].menu. If I swap that out with "http://www.google.com" it works just fine. Also, the links from that variable show up in the console just fine. So I know it's getting the data from the object just fine. But for some reason it doesn't want to open from the div.
FYI I'm extremely new to this so apologies if the explanation doesn't make sense.
var containerDiv = document.getElementById("container");
console.log(containerDiv);
for (var i = 0; i < coffeeShops.length; i++){
var launchMenu = function(){
window.open(coffeeShops[i].menu);
}
console.log(coffeeShops[i].menu);
var coffeeShopDiv = document.createElement("div");
coffeeShopDiv.className = "coffeeShop";
coffeeShopDiv.onclick = launchMenu;
containerDiv.appendChild(coffeeShopDiv);
var coffeeShopImage = document.createElement("img");
coffeeShopImage.src = coffeeShops[i].image;
coffeeShopImage.className = "coffeeImage";
coffeeShopDiv.appendChild(coffeeShopImage);
var coffeeShopHeader = document.createElement("h1");
coffeeShopHeader.className = "coffeeHeader"
coffeeShopHeader.innerHTML = coffeeShops[i].name;
coffeeShopDiv.appendChild(coffeeShopHeader);
var coffeeShopPar = document.createElement("p");
coffeeShopPar.className = "coffeeDescription"
coffeeShopPar.innerHTML = coffeeShops[i].description;
coffeeShopDiv.appendChild(coffeeShopPar);
var coffeeMenu = document.createElement("a");
coffeeMenu.href = coffeeShops[i].menu;
coffeeMenu.innerHTML = "MENU"
coffeeShopDiv.appendChild(coffeeMenu);
};
EDITED: in light of comment
It looks like you need to separate the function which opens the new window from the code which generates page items. By slightly restructuring your code this can be achieved by using the element.addEventListener() method.
/* place the 'launchMenu' outside of
the for-loop so it can be accessed
by each of the target elements */
function launchMenu(event){
/* get the class attribte of
the clicked element */
var clickedClass = event.target.className;
var targetElement,
link;
/* is the clicked element the containing div? */
if (clickClass !== 'coffeeShop') {
/* nope */
targetElement = event.target.parentNode;
} else {
/* yep */
targetElement = event.target;
}
/* get 'data-url' of target */
link = targetElement.getAttribute('data-url');
/* open the new window */
window.open(link);
}
/* elsewhere: create elements as before */
for (var i = 0; i < coffeeShops.length; i++){
var coffeeShopDiv = document.createElement("div");
coffeeShopDiv.className = "coffeeShop";
/* add 'data-' attribute to target div */
coffeeShopDiv.setAttribute('data-url', coffeeShops[i].menu);
containerDiv.appendChild(coffeeShopDiv);
var coffeeShopImage = document.createElement("img");
coffeeShopImage.src = coffeeShops[i].image;
coffeeShopImage.className = "coffeeImage";
coffeeShopDiv.appendChild(coffeeShopImage);
var coffeeShopHeader = document.createElement("h1");
coffeeShopHeader.className = "coffeeHeader"
coffeeShopHeader.innerHTML = coffeeShops[i].name;
coffeeShopDiv.appendChild(coffeeShopHeader);
var coffeeShopPar = document.createElement("p");
coffeeShopPar.className = "coffeeDescription"
coffeeShopPar.innerHTML = coffeeShops[i].description;
coffeeShopDiv.appendChild(coffeeShopPar);
var coffeeMenu = document.createElement("a");
coffeeMenu.className = 'coffeeMenu';
coffeeMenu.innerHTML = "MENU"
coffeeShopDiv.appendChild(coffeeMenu);
/* attach an eventListener to each
created '.coffeeShopDiv' element */
coffeeMenu.addEventListener(
'click', launchMenu, false
);
};
The target element (coffeeShopDiv) now contains a url-reference in its 'data-url' attriubte and has an event listener assigned.
When the target element, or any of her child elements, are clicked the launchMenu() function will be invoked. This function checks which element was clicked by comparing the className attribute to the class name of 'coffeeShopDiv' - such that if the class name of the clicked element is not 'coffeeShop' the targetElement variable is assigned to the clicked elements parent Node (that is, 'coffeShopDiv').
The 'data-url' reference is obtained and used in window.open().
Also see:
Using data-* attributes
Event.target
Quriksmode: Introduction to Events
This StackOverflow answer about using
window.open()
I created a small script that counts images that I uploaded/inserted to my html source code. After I inserted images script creates div containers for those images. If I gave three images, then script will create three divs with class name etc. I have css rule with that class name. This was create before any images were in that container. Everything works but I just can't append those newly images to newly created divs. Is there a way using JavaScript only?
Here is a code:
if (document.getElementsByClassName("Multimedia")[0].getElementsByTagName("IMG")) {
total_number_of_images = document.getElementsByClassName("Multimedia")[0].getElementsByTagName("IMG").length;
for (i = 0; i < total_number_of_images; i = i + 1) {
document.getElementsByTagName("IMG")[i].className = "Image_clip";
child = document.getElementsByTagName("IMG")[i];
image_container = document.createElement("DIV");
image_container.className = "Image_container_div";
document.getElementsByClassName("Multimedia")[0].appendChild(image_container);
document.getElementsByTagName("IMG")[i].style.opacity = "0.8";
}
}
I tried somthenig like this:
image_container.appendChild(child);
But then I can get only two images into container... my third is out and also without className. Without this code, I get className for every image
You should cache the reference to elements rather than querying DOM in loops.
If I understood correctly, Your code should look something like the following for wrapping each image in a container <div>:
var container = document.getElementsByClassName("multimedia")[0];
// if there is only one match, use an id instead ------------^ ?
var images = container.getElementsByTagName("img");
for (var i = 0; i < images.length; i++) {
var img = images[i];
img.className = "imageClip";
img.style.opacity = "0.8"; // Why not define this in imageClip class ..?
imageContainer = document.createElement("div");
imageContainer.className = "imageContainer";
imageContainer.appendChild(img);
container.appendChild(imageContainer);
}
This I get on Yahoo answer. Posted by YaYox: http://jsfiddle.net/ffxad4bq/4
function myFunction() {
var multimedia = document.getElementsByClassName("Multimedia")[0]
var imgs = multimedia.getElementsByTagName("IMG");
for (var i = 0; i < imgs.length; i++) {
imgs[0].className = "Image_clip";
imgs[0].style.opacity = "0.3";
multimedia.innerHTML += '<div class="Image_container_div">'+imgs[0].outerHTML+'</div>';
imgs[0].remove()
}
}
I realized what was the problem. I shouldn't itaret through images. Just leave it on zero because, when loops start, code append one image at a time. When second loop starts I don't have any more 3 images, but two, that is why one image always stays out because loop goes three times.
I'm having a little trouble adding an event listener to elements created dynamically.
I have a list of objects that represent matches a player plays in. And a for loop that iterates through them, creating 4 buttons for each match, a +1, a +2, a -1 and an END button.
However, even if they are well created, and appended where they should be, the event listeners are not kept. Here's a sample of my code:
var container = document.getElementById('container');
for (var i = 0; i < matches.length; i++) {
var row = document.createElement("div");
row.className = "row";
var plusOne = document.createElement("a");
plusOne.id = "plusone_ " + matches[i].id;
plusOne.addEventListener('click', function () {
alert('Clicked on plusOne!')
});
...
// adding plus two, minus one and END the same way
// however, END does have an eventListener on click
row.appendChild(plusOne);
container.appendChild(row);
}
If anyone has any idea why?
I'm trying to retrieve all the elements by class name by using the method getElementsByClassName (no jQuery). Console.log shows the array of the elements, but when I try to get the length of the array, it returns 0.
Saw a previous post with a similar problem that provided a solution of making sure that the element exists. I took this into consideration and fire the function after DOMcreation.
What is going on here?
document.addEventListener("DOMContentLoaded", function(){
// Load current todo items from db
loadTodoItems();
var submitBtn = document.getElementById('submit-btn');
submitBtn.addEventListener('click', addItem);
var removeButton = document.getElementsByClassName("remove-btn");
console.log(removeButton);
console.log(removeButton.length);
}, false)
Another issue to note, is that I am noticing that in chrome Dev Tools when I look at the head tag, I'm seeing that some sort of angular code is being loaded in a script tag in the head, while the content that should be in my head tag are being loaded in the body. I am not using angular for my app.
Edit. Here is my HTML. It is in Jade:
Layout.jade:
doctype html
html(lang='en')
head
meta(charset="utf-8")
title To Do List
link(rel="stylesheet" href="main.css")
body
block content
script(src="main.js")
index.jade:
extends layout
block content
div.container
h1 Get-Er-Done!
form#todo-form(role="form" method="POST" action="/todo")
div.form-group
label(for="addToDo") Add To-Do item:
input#todoItemText.form-control(type="text")
button(type="submit")#submit-btn.btn.btn-default Add
ul#todo-list
Edit. The remove button is for the new todo item. This is called every time the user clicks add to post the new item.
function renderItems(items){
// Before rendering todo-items, clear the existing items in the list
var list = document.getElementById('todo-list');
while(list.hasChildNodes()){
list.removeChild(list.lastChild);
}
// Loop through items
for (var i = 0; i < items.length; i++) {
var el = document.createElement("li");
var removeBtn = document.createElement('button');
var btnText = document.createTextNode('Done');
removeBtn.appendChild(btnText);
removeBtn.className = 'remove-btn';
var newItemText = document.createTextNode(items[i].item);
el.appendChild(newItemText); // Add new content to new div
el.appendChild(removeBtn);
// To-Do list to append to
list.appendChild(el);
}
}
Length is 0 because when you run it there's no element with class remove-btn. You can see the items in the console because getElementsByClassName returns a live HTMLCollection, which is updated when new elements are added.
The problem is that you create the elements with that class in renderItems, which runs after you run getElementsByClassName.
You can fix it using
function renderItems(items){
var list = document.getElementById('todo-list');
while(list.hasChildNodes()){/* ... */}
for (var i = 0; i < items.length; i++) {/* ... */}
// Load current todo items from db
loadTodoItems();
var submitBtn = document.getElementById('submit-btn');
submitBtn.addEventListener('click', addItem);
var removeButton = document.getElementsByClassName("remove-btn");
console.log(removeButton);
console.log(removeButton.length);
}
I have created function for creating a div, when u selet the value in dropdown box , based upon the length the number of divs will be created , so the code is
<select onchange="test()" id="selected_opt">
<option value="0" selected>-Select-</option>
<option value="1">Communication</option>
<option value="2">XXXXXXXXXXXXX</option>
</select>
the function test is
function test(){
var result = get_id.options[get_id.selectedIndex].value;
if(result == 1){
var i = 0,
c = model_details_json.communication,
j = c.length,
communications_div = document.getElementById("model_communication");
if(j == 0){
alert('nothing');
}
for (; i<j; i++){
var communication = c[i];
var create_div = document.createElement('div');
create_div.id = 'communication_id'+i;
create_div.name = 'communication';
var create_anchor = document.createElement('a');
create_anchor.innerHTML = communication.communication_name;
communications_div.appendChild(create_div);
document.getElementById(create_div.id).appendChild(create_anchor);
create_anchor.setAttribute("href", "javascript:void(0);");
create_anchor.setAttribute("onclick","sample('"+communication.communication_name+"','"+create_div.name+"')");
}
}
for example the length is 6 means the six number of divs will be created , so what the problem is when i again click on communication in select dropdown i.e already the six divs have been created , when do it again then agin six divs are created , so totally 12 divs created when u do it again it goes for 6 multiples.......
so what i need is the number of div would not be repeated. and it should be validate whether the user is clicking the same value in dropdown
Check this to remove div elements considering your parent div model_communication.
You need to implement logic by checking if the div exist and stop the loop when you get a message like 'Div is already removed' as shown in the example.
In order to do so create div elements along with id
var newdiv = document.createElement('div');
newdiv.setAttribute('id', id);
You need to remove all divs before create the new ones. Try adding a class name to it:
var create_div = document.createElement('div');
create_div.className = 'communication_div';
...
Now you can select the divs. Before the for statement add these lines to remove the divs with 'communication_div' class name:
var divs = document.getElementsByClassName('communication_div');
for(var i=0; i<divs.length; i++) {
divs[i].parentNode.removeChild(divs[i]);
}
Every script run will generate new divs and remove old ones.
use js map object to put selected value or length as key into the map then everytime user clicks a value, first check for its existence in the map. If not found in the map, that would mean length is not repeating and divs will be created.
something like:
var selectedValues = new Array();
.......
var result = get_id.options[get_id.selectedIndex].value;
if(selectedValues["val_"+result]) {
return;
}
selectedValues["val_"+result] = true;
you can check if the div is already created or present on page using getElementById('elementId') before creating it.
like in you code
for (; i<j; i++){
if(! document.getElementById('communication_id'+i)){ // do if element is not present on page
var communication = c[i];
var create_div = document.createElement('div');
create_div.id = 'communication_id'+i;
create_div.name = 'communication';
var create_anchor = document.createElement('a');
create_anchor.innerHTML = communication.communication_name;
communications_div.appendChild(create_div);
document.getElementById(create_div.id).appendChild(create_anchor);
create_anchor.setAttribute("href", "javascript:void(0);");
create_anchor.setAttribute("onclick",
"sample('"+communication.communication_name+"','"+create_div.name+"')");
}
}
Use replaceChild() instead of appendChild() on the Element object.