I'm trying to find out if it's possible to clone an HTML div with JS, edit it and append it again as a new element. So my source is, for example, this code here:
<div class="wrapper">
<div class="element">
<input id="test--1" value="ABC"/>
</div>
</div>
After copying this element, I need to find a way to change the attribute id of the new cloned input, clear the input value and paste it again in the wrapper so that it looks like this at the end:
<div class="wrapper">
<div class="element">
<input id="test--1" value="ABC"/>
</div>
<div class="element">
<input id="test--2" value=""/>
</div>
</div>
Does that make sense to you? If yes, how can I get this done? Or is it better to assign the content to a variable to append it? I'm looking for the best way here and maybe my idea is a solution too.
You can use pure JavaScript to do this by just cloning the .element div using the cloneNode() method, assign new id and value to the clone div and finally append it back to the document using the insertBefore() method like this:
let x = document.querySelector(".element");
let y = x.cloneNode(true);
y.children[0].id = "test--2";
y.children[0].defaultValue = "";
x.parentNode.insertBefore(y, x.nextSibling);
<div class="wrapper">
<div class="element">
<input id="test--1" value="ABC"/>
</div>
</div>
JSFiddle with the above code: https://jsfiddle.net/AndrewL64/jvc7reza/18/
Based on this answer you could do like:
$('#cloneBtn').on('click', function() {
// get the last input having ID starting with test--
var $inp = $('[id^="test--"]:last'); // Or use :first if you need
// Get parent element
var $div = $inp.closest('.element');
// Create clone
var $div_clone = $div.clone();
// Retrieve number from ID and increment it
var num = parseInt($inp.prop("id").match(/\d+/g), 10) + 1;
// Generate new number and assign to input
$div_clone.find('[id^="test--"]').prop({id: 'test--' + num, value: ''});
// Insert cloned element
$div.after($div_clone); // Or use .before() if you need
});
.element {
padding: 10px;
outline: 2px solid #0bf;
}
<button id="cloneBtn">CLICK TO CLONE</button>
<div class="wrapper">
<div class="element">
<input id="test--1" value="ABC" />
</div>
</div>
Once done inspect the input elements to see the new IDs
<script src="https://code.jquery.com/jquery-3.1.0.js"></script>
Scrambled elements, retrieve highest ID, increment, clone, append.
If your numbered IDs are scrambled, we first need a way to retrieve the highest ID number. Here's an implementation in pure JavaScript:
function cloneElement () {
const inpAll = document.querySelectorAll('[id^="test--"]');
if (!inpAll.length) return; // do nothing if no elements to clone
const maxID = Math.max.apply(Math, [...inpAll].map(el => +el.id.match(/\d+$/g)[0]));
const incID = maxID + 1;
const element = document.querySelector('.element'); // Get one for cloning
const eleClone = element.cloneNode(true);
const inpClone = eleClone.querySelector('[id^="test--"]');
inpClone.id = 'test--'+ incID;
inpClone.value = incID; // just for test. Use "" instead
document.querySelector('.wrapper').prepend(eleClone);
}
document.querySelector('#cloneBtn').addEventListener('click', cloneElement);
.element {
padding: 10px;
outline: 2px solid #0bf;
}
<button id="cloneBtn">CLICK TO CLONE</button>
<div class="wrapper">
<div class="element">
<input id="test--1" value="1" />
</div>
<div class="element">
<input id="test--23" value="23" />
</div>
<div class="element">
<input id="test--7" value="7" />
</div>
</div>
Once done inspect the input elements to see the new IDs
<script src="https://code.jquery.com/jquery-3.1.0.js"></script>
I don't know what data you know, why you want to do such a thing but it can be done :-)
One way is like that:
const elemToCopy = document.getElementById("test--1").parentNode; // I assume you know id
const copiedElem = elemToCopy.cloneNode(true);
const newInput = copiedElem.querySelector("#test--1");
newInput.id = "test--2";
newInput.value = "";
elemToCopy.parentNode.append(copiedElem);
Let me know in a comment if something is not clear :-)
Yes, use jQuery's .clone().
Here is an example that might be relevant to your situation:
let newElement = $('.element').clone();
newElement.find('input').attr('id', 'test--2').val('');
$('.wrapper').append(newElement);
Explanation
In the first line, we created a new cloned element by using jQuery clone().
Then, we found it's child input, changed it's ID and reset the val().
Finally, we found the .wrapper element and appended the new cloned element to it.
Related
I am new to HTML ,JavaScript and jQuery. I am currently doing a search box, when I start to type text on the search input the search list must appear and able to click the search list name and append it to search input, and close the search list and left with search input and current text that I clicked on the search list.
var $block = $('.no-results');
$(".personsMenu").hide();
$(".my-textbox").keyup(function() {
var textbox = document.getElementById("textboxEmp");
var val = $(this).val();
var isMatch = false;
var nameAp = document.getElementsByClassName("name12");
$(".personsMenu").show();
if (textbox.value == 0) {
$(".personsMenu").hide();
}
$(".personsMenu div").each(function() {
var content = $(this).html();
if ((content.toLowerCase().indexOf(val) == -1) && (content.toUpperCase().indexOf(val) == -1)) {
$(this).hide();
} else {
isMatch = true;
$(this).show();
}
});
$block.toggle(!isMatch);
});
function mySelect() {
$(".name12").appendTo($(".my-textbox"));
$(".personsMenu").hide();
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.6.0/jquery.min.js"></script>
<div class="cover">
<div name="selected">
<i class="mdi-account-search mdi"></i><input class="my-textbox" id="textboxEmp" autofocus="autofocus" placeholder="search staff member" />
</div>
<div class="personsMenu">
<ul class="infor">
<div class="nm1" name="selected">
<li class="name12" onclick="mySelect()">Malubane Nyikiwe</li>
<li>nyikiwe.malubane#m-t.co.za</li>
</div>
<div class="no-results">no employee found by that name</div>
<div class="nm1" name="selected">
<li class="name12" onclick="mySelect()">Chamano Sydney</li>
<li>sydney.chamano#m-t.co.za</li>
</div>
<div class="nm1" name="selected">
<li class="name12" onclick="mySelect()">Diphofa Tumelo</li>
<li>tumelo.diphofa#m-t.co.za</li>
</div>
</ul>
</div>
</div>
There's several issues in your code which all need to be addressed:
You're using invalid HTML. ul elements can only contain li, not div. I'd suggest restructuring the HTML to use div containers to hold the information for each item in your list.
Use CSS to hide content which should not be visible when the page loads. This avoids the FOUC which can happen as JS only runs after the DOM is ready.
If you've included jQuery in the page, you may as well use it consistently to make your code more succinct.
Use the input method, not keyup, for listening to user input. input will also fire when the user copies content in to the field using the mouse for example, keyup won't.
Use unobtrusive event handlers, eg. jQuery's on() method, not inline onclick attributes. The latter is outdates and bad practice at it doesn't allow for good separation of concerns.
When searching text, equalise the cases of the search and target strings, don't search for both upper and lower versions.
Use text() to search for the content, not html().
To set the value of an input element use val(), not append(). The latter is for adding HTML/text content to an element, not setting its value property.
With all that said, the working code will look something like this:
var $noResults = $('.no-results');
var $names = $(".name12");
var $personsMenu = $('.personsMenu');
var $searchBox = $(".my-textbox").on('input', function() {
var value = $(this).val().trim().toUpperCase();
if (!value) {
$personsMenu.hide();
return;
}
var matches = $personsMenu.show().find('div').each(function() {
var content = $(this).text().toUpperCase();
$(this).toggle(content.indexOf(value) !== -1);
});
$noResults.toggle(matches.filter(':visible').length == 0);
});
$('.item').on('click', function() {
$searchBox.val($(this).find('.name12').text());
$personsMenu.hide();
});
.personsMenu,
.no-results {
display: none;
}
.item {
padding: 10px;
cursor: pointer;
}
.item:hover {
background-color: #CCC;
}
.item p {
margin: 0;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.6.0/jquery.min.js"></script>
<div class="cover">
<div name="selected">
<i class="mdi-account-search mdi"></i>
<input class="my-textbox" id="textboxEmp" autofocus="autofocus" placeholder="search staff member" />
</div>
<div class="personsMenu">
<div class="no-results">no employee found by that name</div>
<div class="item">
<p class="name12">Malubane Nyikiwe</p>
<p class="email">nyikiwe.malubane#m-t.co.za</p>
</div>
<div class="item">
<p class="name12">Chamano Sydney</p>
<p class="email">sydney.chamano#m-t.co.za</p>
</div>
<div class="item">
<p class="name12">Diphofa Tumelo</p>
<p class="email">tumelo.diphofa#m-t.co.za</p>
</div>
</div>
</div>
I have this code:
<div class="input">
<input type="number" id="myID" oninput="myFunction()">
<div>
<h3>MY TEXT</h3>
</div>
</div>
and I want to make a javascript code to remove the div below the input field whenever I write anything in the input
..........
I tried this code:
function myFunction(){
var field = document.getElementById("myID");
var num = field.value;
var parent = field.parentNode;
parent.innerHTML = field.outerHTML;
field.value = num;
}
but it have a problem each time I make an input, I have to re-click inside the input to make it active again
check out the code here
You should not use inline HTML event attributes to wire up event handlers. That technique is 25+ years old and will not die the death it deserves because people just keep copying it from other code they've seen.
See the comments for the simple explanation:
// Add the event handler to the input in JavaScript, not in HTML
document.getElementById("myID").addEventListener("input", removeElement);
function removeElement(){
// Remove the sibling element that follows the input
document.querySelector("#myID").nextElementSibling.remove();
// Now that the element has been removed, this function is no
// longer required, so remove the event handler to prevent attempts
// to remove it again when it's no longer there. "this" refers to
// the object that caused this function to be invoked (the input
// element in this case).
this.removeEventListener("input", removeElement);
}
<div class="input">
<input type="number" id="myID">
<div>
<h3>MY TEXT</h3>
</div>
</div>
How to remove an HTML element using JavaScript ?
Given an HTML element and the task is to remove the HTML element from the document using JavaScript.
Approach:
Select the HTML element which need to remove.
Use JavaScript remove() and removeChild() method to remove the
element from the HTML document.
Exemple to remove a div :
div.parentNode.removeChild(div);
Follow this link for more information.
I hope I was able to help you.
<div class="input">
<input type="number" id="myID" >
<div id="id2">
<h3>MY TEXT</h3>
</div>
</div>
<script>
document.getElementById("myID").oninput = function() {myFunction()};
function myFunction() {
document.getElementById("id2").innerHTML="";
}
</script>
Problem with using innerHTML is you are basically using a whiteboard. You erase everything on it and you have to redraw it all. That means you would need to reset the value and focus. It is doable, just not practical.
The better thing to do would be to select the element and remove it with .remove()
var field = document.getElementById("myID");
var num = field.value;
if (num.length) {
field.nextElementSibling.remove()
}
It will work, but you will be better off using a class to hide the element. It also has the benefit that if the user deletes the text in the input, you can reshow the message. I would just hide it with a css class with toggle. I would select the div with nextElementSibling.
function myFunction(){
var field = document.getElementById("myID");
var num = field.value;
field.nextElementSibling.classList.toggle('hidden', num.length)
}
.hidden {
display: none;
}
<div class="input">
<input type="number" id="myID" oninput="myFunction()">
<div>
<h3>MY TEXT</h3>
</div>
</div>
I'm trying to find a smart way of clearing previously changed style property on every DOM element.
I know there is a way to clear styles like this
(margin is just an example attribute):
element_name.style.margin = "";
Clearing many elements with many styles attributes this way will take ages, so I hope there is some "all_at_once" solution.
This will clear the style of all tags:
const tags = document.querySelectorAll("*");
for (let i of tags) {
i.style = '';
}
<div style="background-color: beige">
<span style="color: red">Hello</span>
<p style="world">World</p>
</div>
You could also use i.removeAttribute('style'); to remove the style attribute.
You can get all the elements by using
document.querySelectorAll("*")
You will get an object with all the elements with numbered keys. Object.keys will give you an array of all the keys and with forEach you can iterate and apply the style or any manipulation to the elements.
var elem = document.querySelectorAll("*");
Object.keys(elem).forEach((e)=>elem[e].style.margin = "32px")
<div>scscs</div>
This can also be used
document.getElementsByTagName("*");
var elem = document.getElementsByTagName("*");
Object.keys(elem).forEach((e)=>elem[e].style.margin = "")
<div>scscs</div>
The document.getElementsByTagName("*"); shouldn't be used due to performance issues as mentioned by #ScottMarcus in comments
You have to remove inline styles and disable stylesheets:
function clearStyles() {
// remove inline styles:
document.querySelectorAll('*').forEach(e => e.style = null);
// disable stylesheets:
Object.values(document.styleSheets).forEach(v => v.disabled = true);
}
h1 {
color: pink
}
<h1 style="background:navy">My color was set in stylesheet<br>and background was set inline</h1>
<button onclick="clearStyles()">Clear styles</button>
.cssText
.cssText treats the whole value of .style as a string:
document.documentElement.querySelectorAll('*').forEach(tag => tag.style.cssText = '');
This expression will collect all tags within the <html> tag and overwrite all .style properties.
Demo
document.documentElement.querySelectorAll('*').forEach(tag => tag.style.cssText = '');
<div style='color:red'>RED</div>
<div style='color:red'>RED</div>
<div style='color:red'>RED</div>
<div style='color:red'>RED</div>
<div style='color:red'>RED</div>
<div style='color:red'>RED</div>
<div style='color:red'>RED</div>
<div style='color:red'>RED</div>
<div style='color:red'>RED</div>
<div style='color:red'>RED</div>
<div style='color:red'>RED</div>
I want append an input text in my html page. I use JQuery to do that.
My JQuery script :
$(document).ready(function(){
$(".reply").click(function(){
var tempat=$(this).parent().parent().next(".komentar-balasan");
console.log(tempat[0]);
var html=
tempat[0].append('<input type="text"></input>');
});
});
And the HTML :
<div class="isi">
<div class="like-comment">
<div class="kotak"></div>
<div class="kotak-jumlah">
</div>
<div class="kotak"><button class="reply"></button></div>
</div><div class="komentar-balasan"></div>
The Fiddle
I Don't know why, but instead of displayed the input text box. The browser just display <input type="text"></input>. It's like the browser didn't recognize the HTML code.
It's because tempat[0] is accessing the underlying DOM node rather than the jQuery wrapper. It works fine if you omit the array access and just call append on tempat.
You don't need it here but the right way to get a jQuery wrapped element of a jQuery selector list is to use eq
The problem is that you aren't calling the append element on a jQuery object (which treats strings as HTML), but instead on a native DOM element. The experimental ParentNode#append method treats strings as text, so you are seeing text.
If you omit the [0] before calling append, your code runs perfectly:
$(document).ready(function() {
$("#post-komentar").click(function() {
console.log($(this).siblings('.editor-komentar').val());
});
$(".reply").click(function() {
var tempat = $(this).parent().parent().next(".komentar-balasan");
console.log(tempat[0]);
var html =
tempat.append('<input type="text"></input>');
});
});
.reply {
background-color: #fff;
width: 20px;
height: 20px;
margin: 0;
padding: 0;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div class="isi">
<div class="like-comment">
<div class="kotak"><</div>
<div class="kotak-jumlah">
</div>
<div class="kotak"><button class="reply"></button></div>
</div>
<div class="komentar-balasan"></div>
Hello,
Check if this is what you need:
You need to create an element and only then add it.
Here is an example:
$(document).ready(function(){
$(".reply").click(function(){
var tempat=$(this).parent().parent().next(".komentar-balasan");
console.log(tempat[0]);
var newEl = document.createElement('input');
newEl.type = "text";
tempat.append(newEl);
});
});
I hope I have helped!
Remove the [0]. You are dereferencing your jQuery object by doing that.
This works: tempat.append('<input type="text"></input>');
Let's assume we have this HTML structure:
<div id='test-div'>
<div class='random-class-1'>
<div class='useless-element-1'>
</div>
<div class='useless-element-2'>
</div>
<p>Just a paragraph, and useless</p>
</div>
<div class='random-class-2'>
<div class='useless-element-3'>
</div>
<div class='useless-element-4'>
</div>
<div class='useless-element-5'>
</div>
</div>
</div>
I need to select all children "DIV elements" (not grandchildren) inside the first DIV (in this example with id='test-div'), not from document but from element (div) itself.
So, I don't want to use the "query" below because I already have selected the element DIV [object HTMLDivElement]:
// I don't want to use this query
var children = document.querySelectorAll("div > div");
Just an example to achieve this (https://jsfiddle.net/t4gxt65k/):
// I already have selected DIV element
var el = document.getElementById("test-div")
// OR var el = document.querySelectorAll("#test-div");
var children = el.querySelectorAll(":scope > div");
But because of browser incompatibility I don't want to use ":scope"
The real question is:
How can I get the children (only DIV elements) of [object HTMLDivElement] using pure JavaScript?
As an option, you could set a temporary unique attribute for your scope element, and then use querySelectorAll() for its parent with the attribute selector prepended to what you would place after the :scope selector:
// The `scope` variable stores a reference to the scope element.
var attrName = '_scope' + Date.now();
scope.setAttribute(attrName, '');
var children = scope.parentNode.querySelector('[' + attrName + '] > DIV');
I’m not sure about how fast it is though.
Fwiw, specifically for getting child elements, there is the children DOM property:
var children = scope.children;
To get direct children of an element use a combination of parentNode.children or parentNode.childNodes, and Array.prototype.reduce like this:
var children = Array.prototype.reduce.call(el.children, function(acc, e) {
if(e.tagName == "DIV")
acc.push(e);
return acc;
}, []);
Similar to #Ibrahims answer in selecting children but less complicated since it does not address prototype and reduce. Instead it uses Array.from, Array.filter and Element.matches. Element.matches makes it more versatile since it uses a normal selector string (as you would in querySelectorAll).
Array.from(rootElement.children)
.filter(elm => elm.matches('div'))
const rootElement = document.getElementById('test-div')
Array.from(rootElement.children)
.filter(elm=>elm.matches('div'))
.forEach(elm=>elm.classList.add('matched'))
div {
padding: 1rem;
box-shadow: 0 0 0 1px gray inset;
}
.matched {
box-shadow: 0 0 0 1px red inset;
}
<div id='test-div'>
<div class='random-class-1'>
<div class='useless-element-1'></div>
<div class='useless-element-2'></div>
<p>Just a paragraph, and useless</p>
</div>
<div class='random-class-2'>
<div class='useless-element-3'></div>
<div class='useless-element-4'></div>
<div class='useless-element-5'></div>
</div>
</div>