I'm trying to clone an existing layer( $('.total-row').first() ), and then, remove all these layers ( $('.total-row') ), and add some customized layers from the cloned layer.
This is the JS-JQuery code:
$(document).on('click', '.playOnAP',function() {
var clon = $('.total-row').first().clone(true)
$('.total-row').remove();
$('#mp3-list ul li',this).each( function( index, element ) {
$('.jspPane').append(clon);
var totalTitle = $('.total-title').eq(index);
totalTitle.attr('src', $(this).text() ); //url canción
totalTitle.text($(this).text().slice(($(this).text().search("\/[^\/]+$")) + 1)); //canción
totalTitle.siblings( '.total-artist' ).text(artista); //artista
totalTitle.attr('imagen', caratula);
});
}
And here it is the html:
<div class="jspPane" style="padding: 0px; top: 0px; width: 300px;">
<div class="total-row can-play" onclick="" style="background-color: rgb(251, 251, 251);">
<div class="total-checked" onclick="" type="checkbox"></div>
<div class="total-not-playing total-playing"></div>
<div class="total-title" src="http://dcodedmagazine/wp-content/uploads/2013/12/Portishead_-_03_-_Undenied.ogg">titulo canción</div>
<div class="total-artist">artista</div>
<div style="clear:both;"></div>
</div>
<div class="total-row can-play" onclick="" style="background-color: rgb(251, 251, 251);">
<div class="total-checked" onclick="" type="checkbox"></div>
<div class="total-not-playing total-playing"></div>
<div class="total-title" src="http://dcodedmagazine/wp-content/uploads/2013/12/01.-Bored.ogg" imagen="<img src="http://dcodedmagazine/wp-content/uploads/2013/12/AlbumArt_6EC70FCA-D8CB-4DB1-955C-40F2E6CD2AB4_Large-150x150.jpg" class="attachment-100x100 wp-post-image" alt="AlbumArt_{6EC70FCA-D8CB-4DB1-955C-40F2E6CD2AB4}_Large" height="100" width="100">">01.-Bored.ogg</div>
<div class="total-artist">Deftones</div>
<div style="clear:both;"></div>
</div>
<div class="total-row can-play" onclick="" style="background-color: rgb(251, 251, 251);">...
</div>
The problem is that it is adding just the first $('#mp3-list ul li',this) element from $('.playOnAP'), while other sibling layers should be added.
As said in comment, cloning an element returns just a clone so when appending it multiple times, you are just moving the cloned element. As a simple fix, you could append a new clone:
$('.jspPane').append(clon.clone(true));
Related
I've been reading several questions that appear to be similar but didn't find one that resolve my issue or that the suggested solution solved my problem
I have the following html:
<div id="template">
<div class="section1" id="sec1">
<div class="content">
<img id="sec1-is" *ngIf="!tstEnded" src="assets/images/r1.png" srcset="assets/images/r1#2x.png 2x,assets/images/r1#3x.png 3x" >
<img id="sec1-if" *ngIf="tstEnded" src="assets/images/r2.png" srcset="assets/images/r2#2x.png 2x,assets/images/r2#3x.png 3x" />
<div class="audio-controls">
<button *ngIf="do1()" (click)="act1()" class="control-btn r1-btn" [ngClass]="{'disabled':!r1Enabled()}"></button>
<button *ngIf="do2()" (click)="act2()" class="control-btn r2-btn" [ngClass]="{'disabled':!r2Enabled()}"></button>
</div>
<div class="test-wrapper">
<span class="test-line">
{{eta}}
</span>
</div>
<div class="test-wrapper">
<div class="test" tst testType="R" (tstGo)="go($event)"></div>
</div>
</div>
</div>
<div class="section2" id="sec2" style="background-image: linear-gradient(to top, #d0f6f6, rgba(255, 255, 255, 0));">
<div class="content">
<div *ngIf="ended">
<img *ngIf="!open" class="case1" (click)="case1()" src="assets/images/case1c.svg" />
<img *ngIf="open" class="case1" src="assets/images/case1.svg" />
</div>
</div>
</div>
</div>
After cloning the template I wish to change the id attribute of section 1 and 2 as well as the src and srcset of section1 images sec1-is & sec1-if
and change the
let itm = document.getElementById("template");
let cln = itm.cloneNode(true);
How can I get a specific "nested" element without iterating over all the children and grandchildren of template, searching for the correct tag?
Hope this help:
var origin, clone, item;
origin = document.getElementById("template");
clone = origin.cloneNode(true);
item = clone.querySelector("#sec1");
item.setAttribute("id", "sec2");
Overall:
Use querySelector on your clone then setAttribute to update.
Since your img already has id so you can query directly with #sec1-is.
But in general, with querySelector you can have the query string like #sec1 img. Similar to css selector
You can learn more here: https://developer.mozilla.org/en-US/docs/Web/API/Document/querySelector
You can try getting the specific using querySelector() and querySelectorAll() from the cloned element.
Demo:
let itm = document.getElementById("template");
let cln = itm.cloneNode(true);
//get element with .section1
let section1 = cln.querySelector('.section1');
//set id
section1.id = 'sec123'
console.log(section1);
//get element with img in .section1
let img = section1.querySelectorAll('.content img');
//set src of first image
img[0].src = '../test';
//set srcset of first image
img[0].srcset = '../test/test';
console.log(img[0]);
//set src of second image
img[1].src = '../test2';
//set srcset of second image
img[1].srcset = '../test2/test';
console.log(img[1]);
<div id="template">
<div class="section1" id="sec1">
<div class="content">
<img id="sec1-is" *ngIf="!tstEnded" src="assets/images/r1.png" srcset="assets/images/r1#2x.png 2x,assets/images/r1#3x.png 3x" >
<img id="sec1-if" *ngIf="tstEnded" src="assets/images/r2.png" srcset="assets/images/r2#2x.png 2x,assets/images/r2#3x.png 3x" />
<div class="audio-controls">
<button *ngIf="do1()" (click)="act1()" class="control-btn r1-btn" [ngClass]="{'disabled':!r1Enabled()}"></button>
<button *ngIf="do2()" (click)="act2()" class="control-btn r2-btn" [ngClass]="{'disabled':!r2Enabled()}"></button>
</div>
<div class="test-wrapper">
<span class="test-line">
{{eta}}
</span>
</div>
<div class="test-wrapper">
<div class="test" tst testType="R" (tstGo)="go($event)"></div>
</div>
</div>
</div>
<div class="section2" id="sec2" style="background-image: linear-gradient(to top, #d0f6f6, rgba(255, 255, 255, 0));">
<div class="content">
<div *ngIf="ended">
<img *ngIf="!open" class="case1" (click)="case1()" src="assets/images/case1c.svg" />
<img *ngIf="open" class="case1" src="assets/images/case1.svg" />
</div>
</div>
</div>
</div>
How do I make:
document.getElementsByClassName("first")[1].getElementsByClassName("second")[2];
but with querySelector?
My guess would be:
document.querySelector(".first[1] > .second[2]");
But that doesn't work.
In your original selection you're grabbing the second element with the class of .first and the third element with the class of .second that is also the child of the former. With this in mind you could use the nth-of-type pseudo selector for both classes and count up accordingly. The only difference with this method in comparison to the JS you have now is that it doesn't use the zero-index.
// document.getElementsByClassName("first")[1].getElementsByClassName("second")[2];
document.querySelector('.first:nth-of-type(2) .second:nth-of-type(3)').style = 'border: 1px solid red;'
.first {
border: 1px solid black;
padding: 10px;
}
.first:nth-of-type(2) {
margin-top: 10px;
}
<div class="first">
<div class="second">Second (1)</div>
<div class="second">Second (2)</div>
<div class="second">Second (3)</div>
</div>
<div class="first">
<div class="second">Second (1)</div>
<div class="second">Second (2)</div>
<div class="second">Second (3)</div>
</div>
document.querySelector(".first:nth-of-type(2) .second:nth-of-type(3)").style.color = "red"
<div class="first">
<div class="second">second1</div>
<div class="second">second2</div>
<div class="second">second3</div>
<div class="second">second4</div>
</div>
<div class="first">
<div class="second">second1</div>
<div class="second">second2</div>
<div class="second">second3</div>
<div class="second">second4</div>
</div>
You don't need the > operator of the querySelector, you could use the following syntax:
document.querySelector('.first:nth-child(1) .second:nth-child(2)');
Within this HTML code:
var test = document.querySelector('.first:nth-child(1) .second:nth-child(2)').innerText;
console.log(test);
<div class="first">
<div class="second"></div>
<div class="second">Hello, I'm your selected div!</div>
<div class="second"></div>
</div>
<div class="first">
</div>
The JS code will produce the output:
Hello, I'm your selected div!
Keep in mind that CSS pseudoselectors start counting from 1, not from 0, so to achieve the example you posted, you'd need to set :nth-child(2) and :nth-child(3).
Also, if you have a different structure, it might as well be worth taking a look at the :nth-of-type selector, as the :nth-child will require to be the nth child of a parent, in an absolute sense. Differently, :nth-of-type will look for the nth (typeof) child of a parent.
I'm writing a dynamic list and for some reason all my events are triggered using the same ID (all rows of the list can trigger the event, but using the same ID). My rows have different IDs but for some reason, the event is triggered with the latest entry on the list.
Here is the code of the list:
<div class="listContainer" style="width: 100%; overflow-y: auto;">
<div id="card-list" class="container-fluid">
<div class="row row-space" id="row1">
<div class="row-basic" id="rowClass1" style="background-color: rgb(247, 245, 248);">
<div class="circle"></div>
<div class="testTitleContainerBar" style="color: rgb(79, 101, 114);">#1</div>
<div class="totalNumberContainerBar" style="color: rgb(79, 101, 114);">5 Images</div>
<div class="square"><img src="assets/Menu 2-24.png"></div>
<div class="onePixelSeparatorBar"></div>
</div>
<div class="row-advanced" style="height: 0px; visibility: visible;"> </div>
</div>
<div class="row row-space" id="row2">
<div class="row-basic" id="rowClass2">
<div class="circle"></div>
<div class="testTitleContainerBar">#2</div>
<div class="totalNumberContainerBar">5 Images</div>
<div class="square"><img src="assets/Menu 2-24.png"></div>
<div class="onePixelSeparatorBar"></div>
</div>
<div class="row-advanced" style="height: 0px; visibility: visible;"> </div>
</div>
</div>
The event listner is added dynamically like that:
row = document.createElement('div');
row.classList.add('row');
row.classList.add('row-space');
idNumber = total_Tests;
row.id = "row"+idNumber;
row.addEventListener('click', function() {openRow('#'+row.id)});
Can someone help me to understand what's going on?
You are reusing variable row inside a loop, and by the time click handler executes it references the last row. Capture the current id value:
row.addEventListener('click', (function(id) {
return function() { openRow('#'+id); }
})(row.id));
or
row.addEventListener('click', function() {openRow('#'+this.id)});
This code works fine, but I'm guessing there is a better way to rewrite this in either jQuery or vanillaJS.
The main goal is:
To clone specific child elements from parent element
Create new elements with the cloned child
elements
Append newly created elements to new container.
$('.grid-block').each(function(){
var slide = $('<div class="slide"></div>');
$(this).find('.asset-holder img')
.clone()
.appendTo(slide);
$(this).find('.asset-tools')
.clone()
.appendTo(slide);
slide.appendTo('.gallery-slider');
});`
I don't know that you need iteration, just combine your calls to find():
var slide = $('<div class="slide"></div>');
$('.grid-block').find('.asset-holder img, .asset-tools').clone().appendTo(slide);
slide.appendTo('.gallery-slider');
I think, you can use .map()
$('.grid-block').map(function() {
var $this = $(this),
$div = $('<div class="slide"></div>');
$this.find('.asset-holder img')
.clone().appendTo($div);
$this.find('.asset-tools')
.clone().appendTo($div);
return $div.get()
}).appendTo('.gallery-slider');
.gallery-slider {
border: 1px solid red;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div class="grid-block">
<div class="asset-holder">
<img src="//placehold.it/64X64&text=1" />
</div>
<div class="asset-tools">
tools 1
</div>
</div>
<div class="grid-block">
<div class="asset-holder">
<img src="//placehold.it/64X64&text=2" />
</div>
<div class="asset-tools">
tools 2
</div>
</div>
<div class="grid-block">
<div class="asset-holder">
<img src="//placehold.it/64X64&text=3" />
</div>
<div class="asset-tools">
tools 3
</div>
</div>
<div class="gallery-slider"></div>
I want the following:
<div class="contents"></div>
<div class="contents"></div>
<div class="contents">
<span><h3></h3></span>
<span><img></span>
<span><p></span>
</div>
To look like this:
<div class="contents">
<div>
<span><h3></h3></span>
<span><img></span>
</div>
<span><p></span>
</div>
for each of the contents classes. My code:
var contents = $('.page').find('.contents');
var nestedContents = contents.find('span:nth-child(1)');
nestedContents.attr("id", 'h3-location');
var imgContents = contents.find('span:nth-child(2)');
imgContents.attr("id", 'img-location');
$('#img-location, #h3-location').wrap('<div class="groupedContent"></div>');
But all this is doing is wrapping the img and h3 spans in separate groupedContent divs. I have tried wrapAll and it takes ALL the img and h3 spans in the document and puts them in the one groupedContent div in the FIRST contents class. I can't put the img and h3 spans inside the one groupedContent div within each contents class.
Here's a JSFiddle... https://jsfiddle.net/h2awu27c/2/
With HTML code like so...
<div class="contents"></div>
<div class="contents"></div>
<div class="contents">
<span><h3 id="h3-location">The H3</h3></span>
<span><img id="img-location" /></span>
<span><p>asd</p></span>
</div>
<div class="contents">
<span><h3 id="h3-location">The H3 2</h3></span>
<span><img id="img-location" /></span>
<span><p>asd 2</p></span>
</div>
<div class="contents"></div>
To achieve with JS / Jquery, i.e. remove empty .contents divs and wrap the children h3 and img tag inside a groupedContent div:
<div class="contents">
<div class="groupedContent">
<span><h3 id="h3-location">The H3</h3></span>
<span><img id="img-location" /></span>
</div>
<span><p>asd</p></span>
</div>
<div class="contents">
<div class="groupedContent">
<span><h3 id="h3-location">The H3 2</h3></span>
<span><img id="img-location" /></span>
</div>
<span><p>asd 2</p></span>
</div>
Use:
$('.contents').each(function() {
var $contents = $(this);
if ($contents.is(':empty')) {
$contents.remove();
}
else
{
$contents.children('span:has(h3),span:has(img)').wrapAll('<div class="groupedContent"></div>');
}
})
You can use .wrapAll() like below
$('.page .contents').each(function() {
var $contents = $(this);
$contents.children('span:has(h3),span:has(img)').wrapAll('<div class="groupedContent"></div>')
})
.contents {
border: 1px solid red;
padding: 5px;
}
.groupedContent {
border: 1px solid green;
padding: 5px;
}
span {
border: 1px solid blue;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.11.1/jquery.min.js"></script>
<div class="page">
<div class="contents">
<span><h3></h3></span>
<span><img src=""/></span>
<span><p>some p</p>?</span>
</div>
<div class="contents">
<span><h3></h3></span>
<span><img src=""/></span>
<span><p>some p</p>?</span>
</div>
<div class="contents">
<span><h3></h3></span>
<span><img src=""/></span>
<span><p>some p</p>?</span>
</div>
</div>
Note: Your html is invalid, span can't have p as its descendant
Use WrapAll() for the div.content rather than .Wrap(), then select the h3 and img parent span tags again and wrapAll those:
$('div.contents span:nth-child(1),div.contents span:nth-child(2)').wrapAll('<div></div>')
https://jsfiddle.net/x9asccrb/
If I understood your request well, you need this:
JS:
var page = $('.page'),
$contents = page.find('.contents:has(span)').contents(),
item = $contents.wrapAll('<div class="groupedContent"></div>');
$('.groupedContent').clone().appendTo(page.find('.contents:empty'));
HTML:
<div class="page">
<div class="contents"></div>
<div class="contents"></div>
<div class="contents">
<span><h3>H3</h3></span>
<span><img src="#"/></span>
<span><p>P</p></span>
</div>
</div>
So you take a content of a div which :has a span, and wrapping it in another div.groupedContent. Then you are cloning this wrapped content and appending it to the rest of .contents elements (:empty divs).
JSFiddle
Hope this helps