I have cloned div duplicate elements in body with the class name "combo". I need to remove all duplicates except the original div element
The problem is that cloned objects will have the same attributes as the original, so it's rather hard to distinguish them, however, you could try this:
(function()
{
//or indeed: querySelector('.combo') which returns a single DOM ref
var original = document.querySelectorAll('.combo')[0];//reference to the original
//clone and add
function removeClones()
{
var i,all = document.querySelectorAll('.combo');
for(i=0;i<all.length;i++)
{
if (all[i] !== original)
{//this is a clone
all[i].parentNode.removeChild(all[i]);
}
}
}
}());
That should do it. An alternative method would be to add a class to the clones, prior to appending them to the DOM:
var clone = original.cloneNode(true);
clone.className += ' combo-clone';
//then, to remove:
var clones = document.querySelectorAll('combo-clone');//selects all clones
var fn = function(originalEl){
var els = document.querySelectorAll('.combo');
for(var i=0; i<els.length; i++){
if( els[i] !== originalEl ){
els[i].parentNode.removeChild(els[i]);
}
}
}
Keep a reference to the cloned elements somewhere (such as an array). Loop over that array and call foo.parentNode.removeChild(foo) on each value.
Related
Trying to create DOM element "gota" from template. First I create template:
function htmlToElement(html) {
var template = document.createElement('template');
template.innerHTML = html;
return template.content.firstChild;
}
let gota = htmlToElement('<div class="gota"><div class="gota-rastro"><div class="rastro"></div></div><div class="gota-cabeza"></div></div>');
Second, I create collection from CSS class "gotea" and iterate for each element to append template:
function gotear() {
let gotas = document.getElementsByClassName('gotea');
for (let i = 0; i < gotas.length; i++) {
gotas[i].appendChild(gota);
}
}
gotear();
This just add "gota" element to a only one random element of the collection:
How can I add this template to ALL elements in a collection?
You're only creating one element. Then you're using that same element with appendChild multiple times, so you move it from one parent to the next.
You can clone the element with cloneNode(true) and append the clone:
gotas[i].appendChild(gota.cloneNode(true));
Side note: You can use insertAdjacentHTML rather than htmlToElement to insert elements based on that HTML directly:
function gotear() {
let gotas = document.getElementsByClassName('gotea');
for (let i = 0; i < gotas.length; i++) {
gotas[i].insertAdjacentHTML(
"beforeend",
'<div class="gota"><div class="gota-rastro"><div class="rastro"></div></div><div class="gota-cabeza"></div></div>'
);
}
}
gotear();
Granted, that means parsing the HTML repeatedly. But if not useful here, it might be useful elsewhere. (There's also insertAdjacentText.)
I create dynamically a list content:
for (var i = 0; i<length; i++) {
var $li = $('<li />', {
text: ....
}).appendTo($list);
myArray.push($li);
// This doesn't work
$(myArray).click(function (e) { alert('cc'); });
But when I get the parent of the created elements it works
// This works
$('ul.liste').first().find('li').click(function (e) {alert('cc'); });
What's the difference between between $(myArray) and $('ul.liste').first().find('li')?
How to correctly convert a js array to a jquery collection? I thought wrapping the array with $() would work but obviously not.
Instead of pushing, you can use add:
var $set = $();
for (var i = 0; i<length; i++) {
var $li = $('<li />', {
text: ....
}).appendTo($list);
$set = $set.add($li);
}
$set.click(...
If you prefer to build a native array and then convert it to a jQuery collection, then you can do
var $set = $.add.apply($(), myArray);
myArray is native array, You need jQuery object to bind event handler which $('ul.liste').first().find('li') returns thus it works.
You can use .add() to create collection of jQuery object then use it to bind event handler.
//Create empty jQuery object
var myArray = $([]);
var $list = $('.list')
for (var i = 0; i < 5; i++) {
var $li = $('<li />', {
text: i
}).appendTo($list);
myArray = myArray.add($li);
}
// This doesn't work
myArray.click(function(e) {
console.log(this.textContent);
});
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<ul class='list'>
</ul>
You need to loop over the array instead,
Following is incorrect as it is not binding a click event on corresponding element.
$(myArray).click(function (e) { alert('cc'); });
Instead loop as,
$(myArray).each(function(){
$(this).click(function (e) { alert('cc'); });
});
1) What's the difference between between $(myArray) and $('ul.liste').first().find('li')?
Here, myArray is not any jQuery object but a normal array containing jQuery objects as its element. You never bind event to array or string or any other datatype. you always bind event to jQuery object (that contains some DOM elements). Therefore, instead of binding myArray, you should bind every element of myArray one by one.
When you use $('ul.liste'), it works fine because it is a jQuery object with some DOM element in it.
2) How to correctly convert a js array to a jquery collection? I thought wrapping the array with $() would work but obviously not.
You don't convert js Array to jQuery object. But you convert any DOM element to jQuery object as:
For eg,
var elem = document.getElementById("myElem"); // a DOM element
$(elem) //a jQuery object
Arrays are there just to save some data not for DOM manipulations.
I'm looping through a js object with a nested for loop, stated below, it appends the first element correctly, but then throws the following error:
Can't set the property className of an undefined reference or empty reference. (not sure if exact error, translating from Dutch...)
function allVideos() {
var sql = "SELECT videos.VideoName, videos.VideoPath FROM videos";
var resultSet = db.query(sql, {json:true}); //returns: [{"VideoName":"timelapse aethon2","VideoPath":"videos\\Roermond Papier\\160424 Time laps Aethon2.avi"},{"VideoName":"timelapse aethon3","VideoPath":"videos\\Roermond Papier\\160424 Time laps Aethon2.avi"}]
var parsed = JSON.parse(resultSet);
var parsedlength = arrLenght(parsed);
//alert(resultSet);
for(var i = 0; i < parsedlength; i++) {
var obj = parsed[i];
//alert(i);
var videoElement = document.getElementById("allVideos");
for (var key in obj) {
if(obj.hasOwnProperty(key)) {
videoElement.appendChild(document.createElement('div'));
videoElement.children[i].id='allVid' + i;
videoElement.children[i].className='col-md-4 col-xs-12';
//alert(typeof key)
var card = document.getElementById('allVid' + i);
alert(i);
card.appendChild(document.createElement('div'));
card.children[i].className='card card-block';
card.children[i].innerHTML = "<h3 class='card-title'>" + obj['VideoName'] + "</h3><button class='btn btn-primary'>Selecteren</button>"
}
}
}
}
[EDIT] added screenshot of how it looks
Your code has some significant logic issues. You're using nested loops, but appending to an element assuming that the outer loop counter will let you index into that element's children to get the element you just appended. Later, you try to get that same element again using getElementById. Then, you append a new element to your newly-created element, but try to access that new element using children[i] on the one you just created — at that point, the card element will only have a single child, so as of the second outer loop, it will fail.
createElement returns the element to you, so there's no reason at all to try to access it via children[i] (either time) or getElementById.
See comments:
function allVideos() {
var sql = "SELECT videos.VideoName, videos.VideoPath FROM videos";
var resultSet = db.query(sql, {json:true});
var parsed = JSON.parse(resultSet);
var parsedlength = arrLenght(parsed);
for(var i = 0; i < parsedlength; i++) {
var obj = parsed[i];
//alert(i);
var videoElement = document.getElementById("allVideos");
for (var key in obj) {
if(obj.hasOwnProperty(key)) {
// Create the card, give it its id and class
var card = document.createElement('div');
card.id='allVid' + i;
card.className='col-md-4 col-xs-12';
// Create the div to put in the card, give it its class and content
var div = document.createElement('div');
card.appendChild(div);
div.className='card card-block';
div.innerHTML = "<h3 class='card-title'>" + obj['VideoName'] + "</h3><button class='btn btn-primary'>Selecteren</button>"
// Append the card
videoElement.appendChild(card);
}
}
}
}
Side note: arrLenght looks like a typo (it should be th, not ht), but moreover, there's no reason to use a function to get the length of an array; it's available via the array's length property: parsedLength = parsed.length.
Side note 2: You may find these ways of looping through arrays useful.
Your problem is the if within the nested for:
if(obj.hasOwnProperty(key)) { ...
The variable i is increased even if the property is not "owned" (when the if condition returns false), so next time that the condition is true, i is out of bounds.
This question already has answers here:
Get class list for element with jQuery
(16 answers)
Closed 9 years ago.
My items have the following classes:
<div class="class-x some-class-1 other-class"></div>
<div class="some-class-45 class-y"></div>
<div class="some-class-123 something-else"></div>
I'm wondering if there is an easy way to:
Grab only all classes with some-class- prefix.
Remove them from each element.
Have their names (not corresponding DOM elements) in a variable?
I can easily select such elements with jQuery( "div[class^='some-class-'], div[class*=' some-class-']" ) but how its class name could be extracted with the shortest and the most readable code to a variable (can be some global object)?
Like this?
var arrClasses = [];
$("div[class*='some-class-']").removeClass(function () { // Select the element divs which has class that starts with some-class-
var className = this.className.match(/some-class-\d+/); //get a match to match the pattern some-class-somenumber and extract that classname
if (className) {
arrClasses.push(className[0]); //if it is the one then push it to array
return className[0]; //return it for removal
}
});
console.log(arrClasses);
Fiddle
.removeClass() accepts a callback function to do some operation and return the className to be removed, if nothing to be removed return nothing.
You could loop through all the elements, pull the class name using a regular expression, and store them in an array:
var classNames = [];
$('div[class*="some-class-"]').each(function(i, el){
var name = (el.className.match(/(^|\s)(some\-class\-[^\s]*)/) || [,,''])[2];
if(name){
classNames.push(name);
$(el).removeClass(name);
}
});
console.log(classNames);
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div class="class-x some-class-1 other-class"></div>
<div class="some-class-45 class-y"></div>
<div class="some-class-123 something-else"></div>
You can iterate over each found node and iterate over the classes to find a match; if found, remove the class and log it:
var found = [];
$('div[class*="some-class-"]').each(function() {
var classes = this.className.split(/\s+/),
$this = $(this);
$.each(classes, function(i, name) {
if (name.indexOf('some-class-') === 0) {
$this.removeClass(name);
found.push(name);
}
});
});
Note that a selector like div[class*="some-class-"] is pretty expensive and since you need to perform extra processing anyway, it would be easier to just iterate over all div tags and process them:
var elements = document.getElementsByTagName('div'),
found = [];
$.each(elements, function(i, element) {
var classes = element.className.split(/\s+/);
$.each(classes, function(i, name) {
if (name.indexOf('some-class-') === 0) {
$(element).removeClass(name);
found.push(name);
}
});
});
Modern browsers expose Element.classList which you can use to manipulate class names and Array.forEach for iteration:
var found = [];
[].forEach.call(document.getElementsByTagName('div'), function(element) {
(function(names, i) {
while (i < names.length) {
var name = names[i];
if (name.indexOf('some-class-') === 0) {
names.remove(name);
found.push(name);
} else {
++i;
}
}
}(element.classList, 0));
});
The easy way
You clould create your own filter :
$.fn.hasClassStartsWith = function(className) {
return this.filter('[class^=\''+className+'\'], [class*=\''+className+'\']');
}
var divs = $('div').hasClassStartsWith("some-class-");
console.log(divs.get());
See fiddle
I used $('#ul li').get() to get all the list elements and stored in an array, each of this list elements have classes...
var i;
var listClass = ('#ul li').get();
for(i=0;i<listClass.length;i++){
var theClass = listClass[i].attr("class"); //<--what's the proper function/method/code for this?
var content = listClass[i].innerHTML; //<-- works very well
//other codes here
}
How may i able to get the classes of each list elements...Thanks!
You can use jQuery's own map to do that:
alert($('#ul li').map(function() {
return this.className;
}).get());
http://jsfiddle.net/MhVU7/
for example. You can do anything with the returned array.
The reason the way you're doing it isn't working is because you're calling the non-existent method .attr on a native DOM element - it's not an extended jQuery object.
var lis = document.getElementById("ul").children;
for (var i = 0, len = lis.length; i < len; i++) {
var li = lis[i],
className = li.className,
value = li.value,
text = li.textContent;
// code
}
The get() method returns a native array of DOM elements, not a jQuery object.
You should use jQuery:
var lists = $('ul li');
var className = lists.eq(i).attr('class');
var content = lists.eq(i).text();
If you want to loop through all the elements
$('ul li').each(function(){
var className = $(this).attr('class');
var content = $(this).text();
});
I have commented the code to better help you understand it.
$("#ul li").each(function() { /* you should only be using # selector to identify id's - if it's all ul's you want just put ul. */
var klass = this.className; /* this refers to the native DOM object, which contains className */
var textContents = this.innerText || this.textContent; /* the text of the list, does not include html tags */
var childNodes = this.childNodes; /* the child nodes of the list, each unencased string of text will be converted into a TextNode */
console.log(klass + ' ' + textContents); /* replace console.log with alert if you do not have a console */
console.log(childNodes);
});
here is an example of the above.
Good Luck!