Move div content into another div using pure javascript - javascript

I have this HTML setup:
<div class="one">
<div class="text">One</div>
<div class="text">One</div>
</div>
<div class="two">
<div class="text">Two</div>
<div class="text">Two</div>
</div>
I want to move the content of div .two into .one using pure javascript (not jQuery) so we get:
<div class="one">
<div class="text">One</div>
<div class="text">One</div>
<div class="text">Two</div>
<div class="text">Two</div>
</div>
What is the best way to do this with millisecond performance in mind?

I personally prefer insertAdjacentElement as it gives you more control as to where to put elements, but be careful to take note of its browser support.
const one = document.querySelector('.one');
const two = document.querySelector('.two');
[...two.children].forEach(element => {
one.insertAdjacentElement('beforeEnd', element);
});
<div class="one">
<div class="text">One</div>
<div class="text">One</div>
</div>
<div class="two">
<div class="text">Two</div>
<div class="text">Two</div>
</div>
Also note that I've used ES2015 syntax.

The possible duplicate question actually has a native answer - use .appendChild() to move the nodes.
In your case, the code would look like this:
var one = document.querySelector(".one");
var children = document.querySelector(".two").children;
Array.prototype.forEach.call(children, function (child) {
one.appendChild(child);
});
You can loop over it with a while loop and use a DocumentFragment if you're after the performance boost.
var one = document.querySelector(".one");
var children = document.querySelector(".two").children;
var frag = document.createDocumentFragment();
while (children.length) {
frag.appendChild(children[0]);
}
one.appendChild(frag);
Faster solution (source):
var one = document.querySelector(".one");
var children = [...document.querySelector(".two").children];
var frag = document.createDocumentFragment();
var i = 0;
var il = children.length;
while (i < il) {
frag.appendChild(children[i]);
i += 1;
}
one.appendChild(frag);

Pure Javascript, compatible with most browser and old versions, use querySelector as its better in performance to get the first found class instead getElementsByClassName thats returns an array.
var one = document.querySelector('.one');
var two = document.querySelector('.two');
If you want to set it as last children, then:
while(two.children.length>0)
one.appendChild(two.children[0]);
If you want it as first children, then move the content before the first child of one:
while(two.children.length>0)
one.insertBefore(two.children[0], one.firstChild);
And last, useful for similar cases a clean replacement for one could be with:
one.innerHTML = two.innerHTML;
Note: this last implementation removes all content of "one" and sets the content by "two"

Related

How do I loop through HTML DOM nodes?

I want to loop through a nested HTML DOM node, as shown below:
<div id="main">
<div class="nested-div-one">
<div class="nested-div-two">
<div class="nested-div-three">
</div>
</div>
</div>
<div class="nested-div-one">
<div class="nested-div-two">
<div class="nested-div-three">
</div>
</div>
</div>
</div>
How would I do this using Javascript to loop through every single one of the dividers?
I am guessing OP was not specific for DIV elements, here's a more dynamic approach:
So first you wanna get the first container, in your case it's:
var mainEl = document.getElementById('main');
Once you have that, each DOM element has a .children property with all child nodes. Since DOM is a tree object, you can also add a flag to achieve recursive behavior.
function visitChildren(el, visitor, recursive) {
for(var i = 0; i < el.children.length; i++) {
visitor(children[i]);
if(recursive)
visitChildren(children[i], visitor, recursive);
}
}
And now, let's say you want to change all div backgrounds to red:
visitChildren(mainEl, function(el) { el.style.background = 'red' });
You can use vanilla javascript for this
document.querySelectorAll('div').forEach(el => {
// el = div element
console.log(el);
});

Javascript - Strip certain strings from ".innerHTML" result

I have a function that's run on a button click. This function will get all of the HTML inside a certain element. That works fine. However, I would like to clean the returned string (HTML) up before using it further in my function:
exportHTML(){
const element = document.getElementById('content');
const innerHTML = element.innerHTML;
}
This works. But due to using Angular, Angular syntax is included within the HTML based on conditions in the source code. For example:
<div _ngcontent-c1=""></div>
OR
<div ng-reflect-klass="panel album"></div>
<div ng-reflect-ng-class="blue"></div>
Is it at all possible to filter these types of values out? In regards to the second and third example above, the classes within those would change quite often:
Is it possible to filter out and remove all _ngcontent-c1="" text
Is it possible to filter out and remove all ng-reflect-klass & ng-reflect-ng-class including the following open and closed quotes (to remove what's inside)
OK, so the attributes would be constant but the values of the attributes would change? If so, you could try this:
.replace(/ng-reflect-klass=\".?\"/,"").replace(/ng-reflect-ng-class=\".?\"/,"").replace(/_ngcontent-c1=\".*?\"/,"")
var content = 'stuff<div ng-reflect-klass="panel album"></div><div ng-reflect-ng-class="blue"></div><div _ngcontent-c1=""></div>end stuff';
console.log(content.replace(/ng-reflect-klass=\".*?\"/g,"").replace(/ng-reflect-ng-class=\".*?\"/g,"").replace(/_ngcontent-c1=\".*?\"/g,""));
Look at the console to view the result.
You could do it with RegExp
const innerHTML = element.innerHTML.replace(/ (_ngcon|ng-).*?".*?"/g, '');
(_ngcon|ng-) find _ngcon or ng- including space as first character
.*?" match everything until first "
.*?" and match everything again for the closing "
I created a JSFiddle as an example of how to do this without using jQuery.
Using the HTML code below as an example
<div id="origin-content">
<div id="div1" _ngcontent-c1="">Content 1</div>
<div id="div2" ng-reflect-klass="panel album">Content 2</div>
<div id="div3" ng-reflect-ng-class="blue">Content 3</div>
</div>
<hr>
<div id="target-content">
</div>
I extracted all children from origin-content and copied them to target-content using the code that follows.
var result = document.getElementById('target-content');
var elems = document.querySelector('#origin-content').children;
var count = elems.length;
for (var i = 0; i < count; i++) {
var val = elems[i];
val.removeAttribute('_ngcontent-c1');
val.removeAttribute('ng-reflect-klass');
val.removeAttribute('ng-reflect-ng-class');
result.innerHTML += val.outerHTML;
}
There is still plenty of room for improvement.
I hope it helps to solve the OP question.
The following solution will remove all the attributes from element:
You can get all the children first. Then loop through them with forEach(). In each iteration, you can use while loop to removeAttribute() until they are exist in the element.
Try the following way:
function exportHTML(){
const element = document.getElementById('content');
const innerHTML = [].slice.call(element.children);
innerHTML.forEach(function(el){
while(el.attributes.length > 0)
el.removeAttribute(el.attributes[0].name);
});
console.log(document.getElementById('content').innerHTML); // output
}
exportHTML();
<div id="content">
<div _ngcontent-c1=""></div>
<div ng-reflect-klass="panel album"></div>
<div ng-reflect-ng-class="blue" another-test></div>
<span test="test-element"></span>
</div>

swap 2 div's index using pure javascript

I have a parent div and it has 9 same div's am trying to swap two div's index. Following is my code:
HTML:
<div id="cont" class="container">
<div class="no">1</div>
<div class="no">2</div>
<div class="no">3</div>
<div class="blank"></div>
<div class="no">4</div>
<div class="no">5</div>
<div class="no">6</div>
<div class="no">7</div>
<div class="no">8</div>
</div>
now I want to swap say 5th and 6th indexed elements. I have no clue how to do that in JavaScript. I know there is function called .index() but how to do that in pure JS.
Here's one implementation: http://jsfiddle.net/x8hWj/2/
function swap(idx1, idx2) {
var container = document.getElementById('cont');
// ditch text nodes and the like
var children = Array.prototype.filter.call(
container.childNodes,
function(node) {
return node.nodeType === 1;
}
);
// get references to the relevant children
var el1 = children[idx1];
var el2 = children[idx2];
var el2next = children[idx2 + 1];
// put the second element before the first
container.insertBefore(el2, el1);
// now put the first element where the second used to be
if (el2next) container.insertBefore(el1, el2next);
else container.appendChild(el1);
}
This starts by getting a list of all element child nodes, then uses insertBefore to rearrange them.

Close and reopen HTML tags with jQuery

I'm pretty sure this isn't as easy as I wish, but looking for confirmation.
I want to replace an image with a closing div, the image, and the re-opened div.
Here is an example:
http://jsfiddle.net/fdCu5/1/
At the end of the day I want to take HTML that looks like this:
<div class="post">
<div class="constrained">
<p>Hello hello</p>
<img src="http://www.nicenicejpg.com/400/100">
<p>Some more text</p>
</div>
</div>
and make it look like this:
<div class="post">
<div class="constrained">
<p>Hello hello</p>
</div>
<img src="http://www.nicenicejpg.com/400/100">
<div class="constrained">
<p>Some more text</p>
</div>
</div>
Do I need to go up a level and work with it's parent?
http://jsfiddle.net/billymoon/fdCu5/4/
// get reference to the image
var img = $('img')
// get reference to the parent object
var parent = img.parent()
// clone and store parent (should have all same classes and attributes etc...)
var dolly = parent.clone()
// empty the clone
dolly.html("")
// move everything after the image into the clone
dolly.append(img.nextAll("*"))
// put the clone after the parent
parent.after(dolly)
// put the image after the parent (before the clone)
parent.after(img)
Advantage of keeping as objects when moving them round, as opposed to just copying as HTML, is that events should stay bound to the objects even after they are moved.
This method does not rely on prior knowledge of the outer container classes/attributes etc...
Try:
$('.constrained p').wrap('<div class="constrained" />').parent().unwrap();
jsFiddle example
The produces:
<div class="post">
<div class="constrained"><p>Hello hello</p></div>
<img src="http://www.nicenicejpg.com/400/100">
<div class="constrained"><p>Some more text</p></div>
</div>
Just to add another option, here's a merged solution of Billy Moon and j08691's answers. You can just modify the variables as needed to select the children you want to wrap - or you can hard-code it to condense your code.
var containerClass = '.constrained';
var childrenToWrap = '.constrained > *:not(img)';
var container = $(containerClass).clone().empty();
$(childrenToWrap).unwrap().wrap(container);
I figured out a solution that is pretty flexible:
/*
Wide Images
*/
$('img.size-wide').each(function(i,el){
// cache the element
var that = $(el);
// test to see if its a captioned image
if(that.parent().hasClass('wp-caption')) {
that = $(that.parent());
}
var parent = that.parent();
var parentHTML = parent[0].outerHTML;
var childHTML = that[0].outerHTML;
var newHTML = "</div>"; // close the .constrained div to break out
newHTML += childHTML;
newHTML += "<div class='constrained'>"; // open it back up again
parentHTML = parentHTML.replace(childHTML,newHTML);
parent.parent().html(parentHTML);
});

JS target multiple classes and repeat infinitly

The JS below works exactly like it should, my JS knowledge is 0%. Only thing is i need the code below to target multiple divs but same id or different id's does not matter. It also needs to be infinite. so every 50 seconds it needs to repeat. The goal of the js below is to reset CSS3 animations i have running. Project files can be found here: www.dreamsynk.com/img/slider.
// retrieve the element
element = document.getElementById("ani");
setTimeout(function() {
// -> removing the class
element.classList.remove("one");
// -> triggering reflow /* The actual magic */
// without this it wouldn't work. Try uncommenting the line and the transition won't be retriggered.
element.offsetWidth = element.offsetWidth;
// -> and re-adding the class
element.classList.add("one");
}, (50*1000)); //40 seconds
UPDATES:
<div class="slider">
<div class="inner">
<div id="ani" class="one"></div>
<div id="ani" class="two"></div>
<div id="ani" class="three"></div>
<div id="ani" class="four"></div>
<div id="ani" class="five"></div>
<div id="ani" class="six"></div>
</div>
</div>
// retrieve an array-like object with elements
var elements = document.querySelectorAll("ani");
setTimeout(function() {
for (var i=0; i<elements.length; i++) {
var element = elements[i];
element.classList.remove("one two three four five six");
element.offsetWidth = element.offsetWidth;
element.classList.add("one two three four five six");
}
}, (50*1000)); //50 seconds
I am doing something wrong?
You should use document.getElementsByClassName if you want to have an array of elements. document.getElementById normally only gives you the first element of that ID.
The difference between an ID and a class is that an ID can be used to identify one element, whereas a class can be used to identify more than one.
You can also use document.getElementsByName(),
document.getElementsByTagName(),
document.getElementsByTagNameNS() and document.querySelectorAll() of course.
The elements you get from document.getElementsByClassName is known as a HTMLCollection, which is just an array. So if you want to add elements into the collection you can use array.push.
var array = document.getElementsByClassName("classname");
var element = document.getElementById("ani");
array.push(element);
setTimeout(function() {
var i = array.length;
while(i--) {
array[i].classList.remove("one");
array[i].offsetWidth = element.offsetWidth;
array[i].classList.add("one");
}
}, (99999));
Updates:
.classList.remove() can only do 1 class at a time. The same goes
to .classList.add().
What you can do is to create a prototype for DOMTokenList
like this:
DOMTokenList.prototype.addMany = function(classes) {
var array = classes.split(' ');
for (var i = 0, length = array.length; i < length; i++) {
this.add(array[i]);
}
}
and remove/add the classes this way:
element.classList.addMany("one two three four five six");
By the way for .querySelectorAll(selector), you are not using
a proper CSS selector.
You can read more about the syntax of CSS selector here.
And as I have mentioned before, you can't have duplicate ids.
Ids are supposed to be unique.
You can use querySelectorAll to get elements with any css path and then every 50 seconds iterate between them and do the same steps you did for your single element.
Code fixed for your use case:
HTML:
<div class="slider">
<div class="inner">
<div class="ani" id="one"></div>
<div class="ani" id="two"></div>
<div class="ani" id="three"></div>
<div class="ani" id="four"></div>
<div class="ani" id="five"></div>
<div class="ani" id="six"></div>
</div>
</div>
JavaScript:
var container = document.querySelector('slider');
var elements = Array.prototype.slice.call(container.querySelectorAll(".ani"));
setTimeout(function() {
elements.forEach(function(el) { el.classList.remove('ani'); });
container.offsetWidth = container.offsetWidth;
elements.forEach(function(el) { el.classList.add('ani'); });
}, (50*1000)); //50 seconds
// retrieve the elements
var elements = document.querySelectorAll("div");
setInterval(function() {
for(var i = 0; i < elements.length; i++){
// -> removing the class
elements[i].classList.remove("one");
// -> triggering reflow /* The actual magic */
// without this it wouldn't work. Try uncommenting the line and the transition won't be retriggered.
elements[i].offsetWidth = element.offsetWidth;
// -> and re-adding the class
elements[i].classList.add("one");
}
}, (50*1000)); //50 seconds

Categories