Why is this procedure not adding child elements? - javascript

I have a procedure
newRows = JSON.parse(newRowsStr);
var wsr = $('#work-sample-row');
for (var i = 0, n = newRows.length; i < n; ++i)
{
var thisBox = boxHtml;
var thisNewRow = newRows[i];
thisBox.find('.work-item-preview-outer').css('background-image', thisNewRow['imageurl']);
thisBox.find('.work-title').text(thisNewRow['title']);
thisBox.find('.work-descr-short').text(thisNewRow['sumsmall']);
wsr.append(thisBox);
setTimeout(function(){thisBox.css('opacity','0');}, i * 200)
}
where
boxHtml = $('<div class="mb-30-for-mobile col-xxs-12 col-xs-6 col-sm-4 col-md-3 col-lg-3 work-column" style="opacity:0;"><a class="work-link-wrap"><div class="work-item-preview-outer"><div class="work-item-preview-inner"><h3 class="work-title"></h3><p class="work-descr-short"></p></div></div></a></div>');
and what this is meant to do inside the loop is create copies of boxHtml and add some text and styles and then make each of those copies a child of $('#work-sample-row'). I'm not seeing any errors in the console, but I'm also not seeing the children get added. What gives?

When doing thisBox = boxHtml you are not creating a copy, just created a new reference to boxHtml. if boxHtml is a jQuery wrapped element try thisBox = boxHtml.clone(); if it's not a wrapped element do thisBox = $(boxHtml).clone();

Related

How can I build elements dynamically incrementing a number by one?

I am making a gallery. All images are named 1.jpg, 2.jpg, 3.jpg etc - it extends all the way up to 200.jpg.
Copy and paste will be OK, but very time consuming.
<div class="slideshow-container">
<div class="slideshowDisplay fade">
<img src="/images/media/1.jpg" width="100%">
</div>
<div class="slideshowDisplay fade">
<img src="/images/media/2.jpg" width="100%">
</div>
<div class="slideshowDisplay fade">
<img src="/images/media/3.jpg" width="100%">
</div>
Can I use a for-loop or similar to create all the elements for me? My only problem is that, a for loop is used to repeat a code block multiple times is it not, so this for me wouldn't work.
Is there another way that I can create elements without having to spend a long time simply incrementing numbers by hand?
So far I have:
for(var i=0; i < 200; i++){
var newDiv = document.createElement('div');
newDiv.className = 'slideshowDisplay fade';
}
Nothing else...
Any guidance much appreciated.
Basic DOM creation and appending
You're only missing appending the new element to the slideshow-container and adding its content. You can use the i variable to create the increment image src.
var sc = document.querySelector(".slideshow-container")
for(var i=0; i < 200; i++){
var newDiv = sc.appendChild(document.createElement('div'));
newDiv.className = 'slideshowDisplay fade';
var img = newDiv.appendChild(document.createElement("img"));
img.width="100%";
img.src = "/images/media/" + (i + 1) + ".jpg";
}
String concatenation
The means of creating the src is called "string concatenation". In other words, we create a new string from multiple parts. First the "/images/media/" string, then the value of i, but adjusted up by one, and finally the ".jpg" part.
Making helper functions
FWIW, it's nice to have a personal micro-library that you use to handle certain repetitive tasks. One such inclusion can be a function for creating new Elements.
function create(elem, props, par) {
var el = document.createElement(elem)
for (var p in props) {
el[p] = props[p]
}
return par ? par.appendChild(el) : el
}
This takes a little verbosity out of creating and appending the new elements.
var sc = document.querySelector(".slideshow-container")
for(var i=0; i < 200; i++){
var newDiv = create("div", {className: "slideshowDisplay fade"}, sc);
create("img", {width: "100%", src: "/images/media/"+(i+1)+".jpg"}, newDiv);
}
Different approach to a helper function
Or instead of having the function receive the parent to which it is appended, you could allow it to receive an arbitrary number of child elements that it will append to itself.
function create(elem, props, ...children) {
var el = document.createElement(elem)
for (var p in props) {
el[p] = props[p]
}
children.forEach(ch => el.appendChild(ch))
return el
}
Then you can nest calls to create in a way that mirrors the new DOM structure.
var sc = document.querySelector(".slideshow-container")
for(var i=0; i < 200; i++){
sc.appendChild(
create("div", {className: "slideshowDisplay fade"},
create("img", {width: "100%", src: "/images/media/"+(i+1)+".jpg"})
)
);
}
Actually you need just one parent div in your DOM. Then just use functions like document.createElement and appendChild to store the newly created divs with pictures inside the parent element.
var source = "/images/media/";
var parent = document.getElementById('parent');
for (var i = 0; i < 10; i++) {
var newDiv = document.createElement('div');
newDiv.className = 'slideshowDisplay fade';
var img = document.createElement('img');
img.src = source + i + '.jpg';
img.width = '100%';
newDiv.appendChild(img);
parent.appendChild(newDiv);
}
<div class="slideshow-container" id='parent'>
</div>

Div-Element don't refresh after dynamic adding of elements

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.

How to remove wrapper of multiple elements without jquery?

I have a set of elements and want to remove its container wrapper in Javascript.
I've researched around (this, this, and this) but I need a solution that 1) doesn't involve jQuery. 2) and can work on multiple elements.
HTML:
<div class="global-container stacked">
<article class="global"></article>
<article class="global"></article>
</div>
I've tried:
var globalArticles = document.getElementsByClassName('global');
globalArticles.outerHTML = globalArticles.innerHTML;
But that doesn't work. How would one go about removing the wrapper from all article.global?
You could just create your own unwrap() method, something like this
function unwrap(elems) {
elems = 'length' in elems ? elems : [elems];
for (var i = 0; i < elems.length; i++) {
var elem = elems[i];
var parent = elem.parentNode;
var grandparent = parent.parentNode;
grandparent.insertBefore(elem, parent);
if (parent.children.length === 0)
grandparent.removeChild(parent);
}
}
var globalArticles = document.getElementsByClassName('global');
unwrap(globalArticles);
You can use .innerHTML, .removeChild(), .insertAdjacentHTML()
var container = document.querySelector(".global-container");
var html = container.innerHTML; // store `html` of `container`
container.parentElement.removeChild(container); // remove `container`
document.body.insertAdjacentHTML("beforeend", html); // append `html`
<div class="global-container stacked">
<article class="global">1</article>
<article class="global">2</article>
</div>
This should work:
var globalArticle = document.getElementsByClassName('global')[0];
if (globalArticle) {
globalArticle.parentElement.outerHTML = globalArticle.parentElement.innerHTML;
}

Javascript loop over getElementsByClassName

I try to iterate using getElementsByClassName, but the effect i try to achieve affect all the items at once.
How can I make it work 1 item per swipe?
HTML:
<div id="recog" class="cr-wrap">
<div id="slide">
<div class="card item"><img src="mc.svg"></div>
<div class="card item"><img src="paypal.svg"></div>
<div class="card item"><img src="visa.svg"></div>
</div>
</div>
js:
var wrap = document.getElementById('recog');
var swiper = new Hammer(wrap);
swiper.on('swipeleft', function(){
var items = document.getElementsByClassName('item');
for ( var i=0; i < items.length ; i++ ){
items[i].classList.add('gone');
}
});
Maybe this would be better, using querySelectorAll, where you can narrow the hit list even more.
var wrap = document.getElementById('recog');
var swiper = new Hammer(wrap);
swiper.on('swipeleft', function(){
var items = wrap.querySelectorAll('.item');
for ( var i=0; i < items.length ; i++ ){
items[i].classList.add('gone');
}
});
To be noted: By using wrap.querySelectorAll('.item');, it target only item's inside the recog element
Update
If you want only 1 item per swipe, do like this
var wrap = document.getElementById('recog');
var swiper = new Hammer(wrap);
swiper.on('swipeleft', function(){
var item = wrap.querySelector('.item');
item.classList.add('gone');
});
Update 2
If you want only the swiped item, you should be able to do like this but it depends on how hammer pass the target forward.
var wrap = document.getElementById('recog');
var swiper = new Hammer(wrap);
swiper.on('swipeleft', function(e){
e.target.classList.add('gone');
});
If this won't work, you likely need to add a swiper on each item.

How to get Element from Node

From my understanding, document.querySelector returns a Node object. I can then call appendChild on this object.
I execute the following code to append a bunch of divs to my container div:
var container = document.querySelector('.container');
for (var i = 0; i < 400; i++) {
var block = document.createElement('div');
block.className = 'block';
container.appendChild(block);
}
And end up with the following structure:
<div class="container">
<div class="block"></div>
<div class="block"></div>
...
<div class="block"></div>
</div>
How can I loop through each element in my container div and add a new class to it using my existing container variable?
I have tried this:
...
container.childNodes[i].className = 'myClass';
It seems I need to access the Element object of the child Node, but I'm not sure how to do this.
Can you not just add it when you create the divs ?
var container = document.querySelector('.container');
for (var i = 0; i < 400; i++) {
var block = document.createElement('div');
block.className = 'block myClass';
container.appendChild(block);
}
To add classes to the elements in the container variable, I used the following code:
container.children[i].className = 'myClass';
I had to use children instead of childNodes. You can see the context in which this code was used here: http://codepen.io/robkom/pen/RWmodz.

Categories

Resources