I have looked and I still can not figure out how to copy a <p> class named "booking-item-header-price" to the <div> named "myDiv" (basically cloning the <p> to the <div> with JavaScript. It might be important to note that the contents of the <p> class changes based on the price of the item. I have tried some things on JSFiddle but to no avail. Any help would be appreciated.
<p class="booking-item-header-price">
<small>Price</small>
<span class=" onsale">$70.00</span>
<i class="fa fa-long-arrow-right"></i>
<span class="text-lg">$56.00</span>/day
</p>
<div id="myDiv"></div>
If you are wanting to move the element: call appendChild() on the parent element you want to add the element to (#myDiv) with a reference to the element you want to move, your <p> element.
var parent = document.querySelector("#myDiv");
var child = document.querySelector(".booking-item-header-price");
parent.appendChild( child );
If you want to copy the element: use cloneNode() on the child element to make a copy before appending. Pass in true for a deep copy,
var parent = document.querySelector("#myDiv");
var child = document.querySelector(".booking-item-header-price");
parent.appendChild( child.cloneNode(true) );
Note in the copying version you will lose any event listeners you might have applied like through addEventListener()
Demo
var parent = document.querySelector("#myDiv");
var child = document.querySelector(".booking-item-header-price");
parent.appendChild( child.cloneNode(true) );
#myDiv {
padding:30px;
border:1px solid;
}
<p class="booking-item-header-price">
<small>Price</small>
<span class=" onsale">$70.00</span>
<i class="fa fa-long-arrow-right"></i>
<span class="text-lg">$56.00</span>/day
</p>
<div id="myDiv"></div>
function copy(){
document.querySelector('#myDiv').innerHTML =
document.querySelector('.booking-item-header-price').innerHTML;
}
<p class="booking-item-header-price">
<small>Price</small>
<span class=" onsale">$70.00</span>
<i class="fa fa-long-arrow-right"></i>
<span class="text-lg">$56.00</span>/day
</p>
<div id="myDiv"></div>
<button type="button" onclick="copy()">
Copy to #myDiv
</button>
This way we get the innerHTML (all the content including html tags) inside the .booking-item-header-pricep and assign it to the innerHTML of the #myDiv div.
Related
I have a tool that is used for cleaning up crappy HTML in order to make sense of the underlying structure. Having stripped class, style attributes and various Angular attributes, often the resulting markup is a series of nested <div> or <span> elements that have no attributes. What I would like to do is provide option to do a second pass where a <div> or <span> with no attributes can be removed, to flatten the structure more.
Is there a way in JavaScript to confirm that an HTML element has no attributes of any kind?
And if that is possible, how might I approach this stripping of an element?
For example, assuming I have this:
<div>
<div>
<div id="blah">
<div>
<div>
<span dir="auto">
<span>Joe Bloggs</span>
</span>
</div>
</div>
</div>
</div>
</div>
That should end up as:
<div id="blah">
<span dir="auto">
Joe Bloggs
</span>
</div>
Which I would then format to:
<div id="blah">
<span dir="auto">
Joe Bloggs
</span>
</div>
So I'd need a function that can walk the DOM and remove a div (or span) that has no attributes while leaving the inner contents intact (unless of course any of those inner elements can also be stripped for same reason).
Any pointers before I go ahead and construct a shoddy (but working) script would be appreciated!
The attributes property will tell you how many attributes an element has.
const countAttributes = element => console.log({
count: element.attributes.length,
list: [...element.attributes].map(attribute => attribute.name)
});
const divs = document.querySelectorAll('div');
divs.forEach(countAttributes);
<div></div>
<div class="one attribute"></div>
<div class="two attributes" id="second attribute"></div>
Do note that an element without attributes might still be used for something (e.g. a stylesheet might reference it in relation to other elements).
Here's how I did it.
I created a demo element, to get the elements, then I checked the number of elements, I checked if the element should be stripped.
I replaced the element with its children, and if it didn't have any, I used its text
function strip(startElement, toStrip) {
const test = document.createElement('div');
test.innerHTML = startElement.outerHTML;
[...test.querySelectorAll('*')].forEach(elem => {
if (!elem.attributes.length && toStrip.includes(elem.tagName.toLowerCase())) {
if (elem.children.length) elem.replaceWith(...elem.children);
else elem.replaceWith(elem.innerText);
} ;
});
return test.innerHTML;
}
console.log(strip(document.querySelector('div'), ['span', 'div']));
<div>
<div>
<div id="blah">
<div>
<div>
<span dir="auto">
<span>Joe Bloggs</span>
</span>
</div>
</div>
</div>
</div>
</div>
Updated Code
Here you go.
document.querySelectorAll("div").forEach((ele) => {
if (ele.attributes.length === 0) {
var fragment = document.createDocumentFragment();
while (ele.firstChild) {
fragment.appendChild(ele.firstChild);
}
ele.parentNode.replaceChild(fragment, ele);
}
});
<div>
<div>
<div id="blah">
<div>
<div>
<span dir="auto">
<span>Joe Bloggs</span>
</span>
</div>
</div>
</div>
</div>
</div>
So final output would be
<div id="blah">
<span dir="auto">
<span>Joe Bloggs</span>
</span>
</div>
I have the below HTML structure.
<div class="SomeClassName">
<a href="https://abc.xyz">
<span>
<img id="SomeImgID1" />
</span>
</a>
<a href="https://xyz.abc">
<span>
<img id="SomeImgID2" />
</span>
</a>
</div>
I want to append <div> tag before each <img> tag, how do I do it with pure javascript?
Something like
let divElement=document.querySelection('div.someClass');
Array.from(divElement.querySelectionAll('img'))
.forEach(el=>divElement.insertBefore(document.createElement('div'),el));
Again, if you want to wrap img then you can use next snippet:
let divElement=document.querySelection('div.someClass');
Array.from(divElement.querySelectionAll('img'))
.forEach(el=>{
let div=document.createElement('div');
divElement.insertBefore(div,el));
div.appendChild(el);
});
For more information see Element.insertBefore on MDN
iaMsUPerNOva finally i got you and i am here with solution .
<a class="image" href="https://abc.xyz"> <!--note this-->
$(function() {
var node = $("a.image"); // This will copy your a tag so that img tag will also get copied.
$(".SomeClassName").append('<div>hello</div>');//This will create a new div containing hello text
$("a.image").remove(); // This will remove a tag which is already copied to node.
$("SomeClassName").append(node); //Finally we are going to add newly created div to SomeClassName.
});
Okay, so what we want to do here involves two steps:
Find each IMG element inside your DIV with class SomeClassName.
For each of these IMG elements, create a new DIV and insert it before the element.
Here is how you do that.
/* document.querySelectorAll returns a NodeList.
The spread operator "..." converts it into an array,
so that we can call the forEach method on it. */
[...document.querySelectorAll("div.SomeClassName img")].forEach(x => {
// Here we create the new DIV
let div = document.createElement("div");
// Just some sample text to show
div.textContent = "Hello!";
// x.parentNode finds the parent of the IMG element.
// The frst parameter of node.InsertBefore is the
// element we want to insert as its child, and the
// the second parameter is the reference element
// before which this new element will be inserted
x.parentNode.insertBefore(div, x);
});
Thank you, everyone, for your responses. I forgot to mention before that I had another parent <div> and the final structure was like this.
<div class="ParentClassName">
<div class="ChildClassName">Some Content</div>
<div class="ChildClassName">Some Content2</div>
<div class="ChildClassName">
<a href="https://abc.xyz">
<span>
<img id="SomeImgID1" />
</span>
</a>
<a href="https://xyz.abc">
<span>
<img id="SomeImgID2" />
</span>
</a>
</div>
</div>
I could able to wrap all <img> tags inside <div> by doing the below step.
Note: If your classname is dynamic you can remove it from the query selectors and you can put only the selector element like document.querySelector("div");
let divElement = document.querySelector("div.ParentClassName");
Array.from(divElement.querySelectorAll("div.ChildClassName img")).forEach(
(el) => {
let div = document.createElement("div");
el.parentElement.insertBefore(div, el);
div.appendChild(el);
}
);
and my final output was
<div class="ParentClassName">
<div class="ChildClassName">Some Content</div>
<div class="ChildClassName">Some Content2</div>
<div class="ChildClassName">
<a href="https://abc.xyz">
<span>
<div>
<img id="SomeImgID1" />
</div>
</span>
</a>
<a href="https://xyz.abc">
<span>
<div>
<img id="SomeImgID2" />
</div>
</span>
</a>
</div>
</div>
I am trying to create portlets on my website which are generated when a user inputs a number and clicks a button.
I have the HTML in a script tag (that way it's invisible). I am able to clone the HTML contents of the script tag and append it to the necessary element without issue. My problem is, I cannot seem to modify the text inside the template before appending it.
This is a super simplified version of what I'd like to do. I'm just trying to get parts of it working properly before building it up more.
Here is the script tag with the template:
var p = $("#tpl_dashboard_portlet").html();
var h = document.createElement('div');
$(h).html(p);
$(h).find('div.m-portlet').data('s', s);
$(h).find('[data-key="number"]').val(s);
$(h).find('[data-key="name"]').val("TEST");
console.log(h);
console.log($(h).html());
console.log(s);
$("div.m-content").append($(h).html());
<script id="tpl_dashboard_portlet" type="text/html">
<!--begin::Portlet-->
<div class="m-portlet">
<div class="m-portlet__head">
<div class="m-portlet__head-caption">
<div class="m-portlet__head-title">
<h3 class="m-portlet__head-text">
<span data-key="number"></span> [<span data-key="name"></span>]
</h3>
</div>
</div>
<div class="m-portlet__head-tools">
<ul class="m-portlet_nav">
<li class="m-portlet__nav-item">
<i class="la la-close"></i>
</li>
</ul>
</div>
</div>
<!--begin::Form-->
<div class="m-portlet__body">
Found! <span data-key="number"></span> [<span data-key="name"></span>]
</div>
</div>
<!--end::Portlet-->
</script>
I'm not sure what I'm doing wrong here. I've tried using .each as well with no luck. Both leave the value of the span tags empty.
(I've removed some of the script, but the variable s does have a value on it)
You have two issues here. Firstly, every time you call $(h) you're creating a new jQuery object from the original template HTML. As such any and all previous changes you made are lost. You need to create the jQuery object from the template HTML once, then make all changes to that object.
Secondly, the span elements you select by data-key attribute do not have value properties to change, you instead need to set their text(). Try this:
var s = 'foo';
var p = $("#tpl_dashboard_portlet").html();
var $h = $('<div />');
$h.html(p);
$h.find('div.m-portlet').data('s', s);
$h.find('[data-key="number"]').text(s);
$h.find('[data-key="name"]').text("TEST");
$("div.m-content").append($h.html());
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<script id="tpl_dashboard_portlet" type="text/html">
<div class="m-portlet">
<div class="m-portlet__head">
<div class="m-portlet__head-caption">
<div class="m-portlet__head-title">
<h3 class="m-portlet__head-text">
<span data-key="number"></span> [<span data-key="name"></span>]
</h3>
</div>
</div>
<div class="m-portlet__head-tools">
<ul class="m-portlet_nav">
<li class="m-portlet__nav-item">
<i class="la la-close"></i>
</li>
</ul>
</div>
</div>
<div class="m-portlet__body">
Found! <span data-key="number"></span> [<span data-key="name"></span>]
</div>
</div>
</script>
<div class="m-content"></div>
In my case only this is working:
var template = $('template').clone(true, true); // Copies all data and events
var $h = $('<div />');
$h.html(template);
$h.find('.input-name').attr('value', "your value here"); // Note: .val("your value here") is not working
$('.list').prepend($h.html());
I have this tag:
<td align="center">
<div class="dropdown">
<button onclick="DropdownShow(this)" class="btn btn-default glyphicon glyphicon-picture"></button>
<div id="#TableRowId" class="dropdown-content">
Show
Edit
</div>
</div>
</td>
and JS function:
function DropdownShow(element) {
var elm = document.getElementById(element.querySelector(".dropdown-content").id);
elm.classList.toggle('show');
}
I want when I click on the image glyphicon at the table, to show the dropdown div tag with the class="dropdown-content". To do that I need the each row ID, and I have it on the variable #TableRowId. How can I do that?
You are passing the reference of clicked button so you need to get the element by getting its parent element where parent node can get from parentNode property.
function DropdownShow(element) {
var elm = element.parentNode.querySelector('.dropdown-content')
elm.classList.toggle('show');
}
FYI: If there is no whitespace after the button then you can use nextSibling property to get the element.
var elm = element.nextSibling;
or use nextElementSibling property to get the element even there is a text node.
var elm = element.nextElementSibling;
Check polyfill option for ie8.
I would pass the #TableRowId to the button as a data attribute like this:
<td align="center">
<div class="dropdown">
<button data-dropdown-content-id="#TableRowId" onclick="DropdownShow(this)" class="btn btn-default glyphicon glyphicon-picture"></button>
<div id="#TableRowId" class="dropdown-content">
Show
Edit
</div>
</div>
</td>
And then your javascript would simply be:
function DropdownShow(element) {
var dropDownContentId = element.getAttribute("data-dropdown-content-id");
var elm = document.getElementById(dropdownContentId);
elm.classList.toggle('show');
}
This would give you the most robust code, because it doesn't depend on the relationships (sibling/parent/child etc) between the two elements.
I have a problem with getting a html() value of child of a parent :D
function voteup(e){
var count = $(e).parents('.item').children('.count');
console.log(count.html()); // undefined
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div class="post_contain">
<img src="images/comments/dQ6dz.jpg" alt="">
</div>
<div class="item">
<p class="post-meta">
<span href="/gag/agVzE1g" target="_blank">
<span class="count">5</span>points
</span>
</p>
<div class="vote">
<ul class="btn-vote left">
<li class="badge-item-vote-up-li">
<a onclick="voteup(this)">Click me</a>
</li>
</ul>
</div>
</div>
In the function voteup(e), I need to get the value of the class 'count', but I don't retrieve the value with html()
children only traverses a single level of the DOM tree - i.e. it won't find grandchildren.
Instead, use closest to find the .item -- which finds the single nearest match, as opposed to parents which can find multiple -- and find to locate the child, since that will traverse arbitrarily deep HTML structures:
function voteup(e){
var count = $(e).closest('.item').find('.count');
alert(count.html());
var actual = parseInt(count.html(), 10);
count.text(actual + 1);
}