Indexing in .children list not working as expected - javascript

Could anyone please explain why for the given HTML
<body>
<div id="ustack1">
Block 1:
<div id="0"> 0 </div>
<div id="1"> 1 </div>
<div id="2"> 2 </div>
<div id="3"> 3 </div>
<div id="4"> 4 </div>
<div id="5"> 5 </div>
<div id="6"> 6 </div>
<div id="7"> 7 </div>
<div id="8"> 8 </div>
<div id="9"> 9 </div>
<div id="10"> 10 </div>
</div>
<div id="stagingDiv" style="display:inline-block;">
Block 2:
</div>
</body>
And the corresponding javascript
var cards = document.getElementById("ustack1").children;
for(i=0;i<cards.length;i++){
document.getElementById("stagingDiv").appendChild(cards[i]);
}
(As seen in this jsfiddle: https://jsfiddle.net/73oszkj9/ )
that the odd elements are being skipped over?

cards is a live HTMLCollection. When you perform the appendChild, you're moving the node to another place in the DOM, which removes it from the collection. One solution is to just iterate over cards until its length is zero:
while(cards.length > 0){
document.getElementById("stagingDiv").appendChild(cards[0]);
}
Here's an updated fiddle: https://jsfiddle.net/Lkvdep52/
If it makes you feel any better, this is a mistake that many of us have made at one time or another ;-) Using the browser debugger is a good way to understand the underlying cause for problems like this.

When you use pure appendChil you are cutting the exact element from its parent. Add cloneNode to make a copy of that elements:
var cards = document.getElementById("ustack1").children;
for(i=0;i<cards.length;i++){
document.getElementById("stagingDiv").appendChild(cards[i].cloneNode(true));
}
At the end you can remove children of first parent if needed.

Related

I want to swap 2 identical HTML elements with JavaScript

I'm having some problems swapping two HTML elements in JavaScript. In the HTML below I want to switch the divs with id of "ans1" with that of id "ans2" using the buttons with id "down1" and "up1".
I don't want to specifically select "ans1" and "ans2" because this is an ordering quiz and the first child element of container 1 and 2 may need to be moved again using these same buttons.
<div id="quiz" class="quiz-container d-none">
<div id="question" class="quiz-question"></div>
<div id="container1" class="answer-container">
<div id="ans1" class="answer"></div>
<div class="button-container">
<button id="down1" class="down first-button"><i class="fas fa-chevron-down"></i></button></div>
</div>
<div id="container2" class="answer-container">
<div id="ans2" class="answer"></div>
<div class="button-container">
<button id="up1" class="up1"><i class="fas fa-chevron-up"></i></button><button id="down2" class="down"><i class="fas fa-chevron-down"></i></button>
</div>
In JavaScript I've been trying various versions of the code below. Sometimes the two elements just disappear and sometimes the whole parent element switches position instead of just the child. Can anyone please let me know the correct syntax for switching these two elements so that the child elements can be switched multiple times using the same button?
$('#container1:first').appendTo( $('#container2') );
Pretty easy to do with vanilla JS.
document.getElementById('btn').addEventListener('click', () => {
const c1 = document.getElementById('c1');
const c2 = document.getElementById('c2');
c2.appendChild(c1.firstElementChild);
c1.appendChild(c2.firstElementChild);
});
<div id="c1">
<div>item 1</div>
</div>
<div id="c2">
<div>item 2</div>
</div>
<button id="btn">switch</button>
N.B. this relies on the fact that I'm appending an element to the end of the container, so the firstElementChild will still pick up the correct element. You can store these elements in vars before you do the swapping if needed.
I think that this link will help you to solve your problem
How to swap div using Jquery .
Apparently you can not set two divs with the same id using jquery that is why he set a third variable to achieve his goal
Thank you for your response. The code works to a certain extent. When I push my "down1" button the 2 elements do switch positions but when I push it again to swap them back, the buttons instead switch positions. When I push the button again(which is now in a wrong position)the elements then switch back and I have to push the button a 4th time to get the buttons back to the way they were too. I've also tried to select a 2nd Id "up1" button to also carryout the same function but this button doesn't work at all. Do you have any ides on on to fix this. I'll share my current code below
document.getElementById("down1", "up1").addEventListener('click', () => {
answerTwoContainer.appendChild(answerOneContainer.firstElementChild);
answerOneContainer.appendChild(answerTwoContainer.firstElementChild);
});
<div id="quiz" class="quiz-container d-none">
<div id="question" class="quiz-question"></div>
<div id="container1" class="answer-container">
<div id="ans1" class="answer"></div>
<div class="button-container">
<button id="down1" class="down first-button"><i class="fas fa-chevron-down"></i></button></div>
</div>
<div id="container2" class="answer-container">
<div id="ans2" class="answer"></div>
<div class="button-container">
<button id="up1" class="up"><i class="fas fa-chevron-up"></i></button><button id="down2" class="down"><i class="fas fa-chevron-down"></i></button>
</div>
</div>

Elegant way of arranging items

Here is the fiddle I'm working with:
http://jsfiddle.net/g2Zus/
Here is the html code:
<div class="container">
<div class="right">
<div id="cityList" class="inner-table"></div>
</div>
<div class="left">
<div id="cityList2" class="inner-table"></div>
</div>
<div class="middle">
<div id="cityList3" class="inner-table"></div>
</div>
</div>
My questions are:
Is there a way to elegantly arrange(explanation like how is given in second point) them (like not fixing the number of columns as I did in this example).
If 'n' be the number of elements in the array(assuming the number is not fixed) and if n is an even number divide the screen such that it has same number of elements in all the rows and if n is odd the extra element can occupy the entire last row.

Converting from working function in console to working script. (See Edit)

I'm trying to automate a clicking of a link within a class list. Currently I have a working script that will pick the first item in the container using the querySelector(), one line of code wrapped in a function.
To have more usability, I was wondering if I could modify the code so that the script searches within each item in the container trying to match a title of the listing or name with a defined variable, to the users desire, and once found, clicks the link for that particular item.
<div class="item-wall">
<div class="grid-item" data-column-index="0" data-pdpurl="http://www.LINK1.com">
<div class="grid-item"> … </div>
<div class="content">
<div class="grid-item-details-wrapper">
<div class="grid-item-image"> … </div>
<div class="grid-item-info-wrapper no-chipper">
<a href="http://www.LINK1.com">
<div class="product-name">
<p class="griditem-display-name nsg-font-size--regular nsg-text--dark-grey">
PRODUCT1
</p>
<p class="griditem-subtitle nsg-font-size--regular nsg-text--medium-grey"> … </p>
</div>
<div class="product-price-wrapper"> … </div>
</a>
</div>
<div class="grid-item-extras"> … </div>
</div>
</div>
</div>
<div class="grid-item" data-column-index="1" data-pdpurl="http://www.LINK2.com">
<div class="grid-item"> … </div>
<div class="content">
<div class="grid-item-details-wrapper">
<div class="grid-item-image"> … </div>
<div class="grid-item-info-wrapper no-chipper">
<a href="http://www.LINK2.com">
<div class="product-name">
<p class="griditem-display-name nsg-font-size--regular nsg-text--dark-grey">
PRODUCT2
</p>
<p class="griditem-subtitle nsg-font-size--regular nsg-text--medium-grey"> … </p>
</div>
<div class="product-price-wrapper"> … </div>
</a>
</div>
<div class="grid-item-extras"> … </div>
</div>
</div>
</div>
<div class="paging-bar hidden"> … </div>
<div class="spacer"></div>
</div>
Sorry for being so verbose. The web page has an 'item-wall' with several items, 2 are only shown here. I wish to be able to set a variable as a string in the script and be able to use something along the lines of .contain() to find an instance of the matching product name in the wall and then have it open the link corresponding to the selection.
Thanks for any input!
/////////////////////////////////////////////////////////////////////////////////////////////
EDIT: Thanks to #Barmar for the working console function:
function product_click(product) {
$(".griditem-display-name:contains("+product+")").closest("a").click();
}
product_click("Desirable here")
Now I am at a loss as to how to make this function operational in an script. I've tried with scriptish in firefox and have tried writing this to a .js file and loading it as an unpacked extension in chrome to no avail. It seems as though the function/script won't load. If anyone has any thoughts, they'd be greatly appreciated.
Thanks again!
If I understand you correctly, I think this is it:
function product_click(product) {
$(".griditem-display-name:contains("+product+")").closest("a").click();
}

Need explanation of jQuery code

Can someone please explain the structure of this line of a script for me? Another user on here has written it as part of a function that I know want to edit and change to use elsewhere on my site.
$('#main_content .img-wrapper').empty().append($(this).find('img').clone());
This one takes an image from one div and copies it to another with the class="img-wrapper"
I want to do exactly the same but with text. I tried this
$('#main_content .text-wrapper').empty().append($(this).find('.info').clone());
where ('.info') is the class name of the div I want to copy. Its not working.
I don't fully understand the syntax as this is my first day using javascript. Please can someone explain where I'm going wrong?
This is the HTML - There are four different images and when the user clicks on each of the image I want it to load the same image and associated text in the main content div
<div class="row">
<div class="card-container">
<div class="card">
<div class="back">
<img src="images1.png" />
<div class="info" style="display: none;">This is a test for image one</div>
</div>
<div class="front" style="background-color:#cc99cc;"></div>
</div>
</div>
<div class="card-container">
<div class="card">
<div class="back">
<img src="images2.png" />
<div class="info" style="display: none;">This is a test for image one</div>
</div>
<div class="front" style="background-color:#9966cc;"></div>
</div>
</div>
<div class="card-container">
<div class="card">
<div class="back">
<img src="images3.png" />
<div class="info" style="display: none;">This is a test for image one</div>
</div>
<div class="front" style="background-color:#6666cc;"></div>
</div>
</div>
<div class="card-container">
<div class="card">
<div class="back">
<img src="images4.png" />
<div class="info" style="display: none;">This is a test for image one</div>
</div>
<div class="front" style="background-color:#3366cc;"></div>
</div>
</div>
This is the main content div
<div id="main_content">
<!-- main content -->
<div class="img-wrapper">
</div>
<div class="text-wrapper">
</div>
</div>
The javascript in question is using jQuery.
$('#main_content .img-wrapper')
returns the element(s) with class 'img-wrapper' inside the element with id 'main_content'
.empty()
empties this element (removes all it's HTML contents)
.append(
inserts the argument (the bit that comes next) into this element
$(this).find('img')
finds all 'img' tags within the element referred to by this (i.e. if this was triggered from a .click() handler then the element that was clicked)
.clone()
clones these elements so that there are two versions - one in their original location and one being inserted into the #main_content img-wrapper element.
);
Do you definitely have a #main_content .text-wrapper element?
Without seeing the html structure, my guess would be the context in which you're trying to find .info is incorrect.
I'm assuming this block of code is within an event handler like a click or mouseover or something. In that case the $(this) is referring to the element that triggered that event. So the following snippet:
$(this).find('.info')
is looking for elements with a classname of info within the element referred to by $(this).
Make sure the context is correct - change $(this) to the element that you need to search within.
Try this:
$('#main_content .text-wrapper').empty().append($(this).find('.info').html());

Help me optimize this jQuery :has selector

I'm using dynaTrace to profile my application in Internet Explorer.
One of the most expensive calls is the following:
$("div.containerClass:has(div.containerHeader)")
I scoped the selector as follows, which offered a little improvement:
$("div.containerClass:has(div.containerHeader)", "#section-wrapper")
How can I improve the performance further?
NOTE: I CANNOT change the HTML markup, only the JavaScript.
I'm using jQuery 1.4.2.
UDPATE
Here is sample HTML... note that in my actual application, the HTML is dynamic and the actual markup will vary:
<div id="section-wrapper">
<div class="somethingelse">
<div class="somethingelse2">
<div class="containerClass">
<div class="containerHeader">
<h2>content region 1</h2>
</div>
</div>
<div class="containerClass">
<div>
<h2>content region 2</h2>
</div>
</div>
<div class="containerClass">
<div class="containerHeader">
<h2>content region3 </h2>
</div>
</div>
<div class="containerClass">
<div class="containerHeader">
<h2>content region 4</h2>
</div>
</div>
</div>
</div>
You should use a single selector, like this:
$("#section-wrapper div.containerClass:has(div.containerHeader)")
Otherwise you're firing up multiple jQuery objects just to perform a find. You'll have to test, but depending on the DOM you're working against, this can be much faster (especially in jQuery 1.4.3+):
$("#section-wrapper div.containerHeader").closest("div.containerClass")
While it would be silly if this is indeed faster, have you tried:
$("div.containerClass > div.containerHeader").parents('div.containerClass')
on edit: Added parent selector.

Categories

Resources