Element still child of previous parent after moving it - javascript

Answer in short: insertAfter() is to be used on the element that you are inserting after another element, not on the element that you want to insert something after. For full code, scroll down.
I have a situation where when the user clicks a button, certain elements get moved to a hidden container, and when the user clicks another button, those elements need to get moved back to their original position.
I do it (in short) like this:
Moving to hidden container:
element.data('original_parent', original_parent);
element.data('original_index', original_parent.index());
element.appendTo(hidden_container);
Moving the items back to their original container:
element.data('original_parent').children().eq(element.data('original_index')).prev().insertAfter(element);
But somehow this isn't working. When I output the children of the original parent to the console, it also lists the elements that are currently in the hidden container as children. Anyone have an idea of how I could fix this?

Your logic may not be not correct as the order in which it is removed and added might deffer – Arun P Johny 1 min ago
You are right. The elements are output to the console first, then I move them, which is why it seemd like an uncorrect parent was being listed as their parent.
Are you sure you're getting any element with doing element.data('original_parent')? – Dhaval Marthak 5 mins ago
An element is being returned for sure.
I have already found out what is happening here. I use the insertAfter function on the original element that I want to insert the element after instead of on the element that I want to insert after the original element. Got my jQuery functions mixed up a bit.
The rest of the code works, though! Full code for those that want to use the idea and come across this post:
function hideNonMatchingLevelElements(jquery_selector) {
var elements = $(jquery_selector);
if (!elements.length)
return false;
var target = $('#js-hidden-level-elements');
if (!target.length) {
console.error('Cannot hide non matching level elements because target cannot be found.');
return false;
}
elements.each(function() {
$(this).data('original_parent', $(this).parent());
$(this).data('original_index', $(this).index());
$(this).appendTo(target);
});
}
function showMatchingLevelElements(jquery_selector) {
var elements = $(jquery_selector);
if (!elements.length)
return false;
elements.each(function() {
// Only show elements that are in the "hidden elements" container.
if ($(this).parent().attr('id') != 'js-hidden-level-elements')
return true; // Continue;
if (!$(this).data('original_parent'))
return true; // Continue.
$(this).insertAfter($(this).data('original_parent').children().eq($(this).data('original_index')).prev());
});
}

Related

How to iterate over elements of same class to find first visible

If I had multiple objects of a class present, but only some are visible, what would be the best way to find the first visible one. I currently try:
browser.waitForElementVisible('.myClass', timeOut)
which sees all of the elements, but will only act on the first found. OR
browser.waitForElementVisible('(//div[#class="myClass"])[1]')
which specifies an index, but that may or may not be visible, since new data is loaded every time the page refreshes.
I need to loop through all present and just click on the first instance of one that is visible. I know I can achieve this through custom commands, but I'm new to js and nightwatch, so I'm not sure how to go about it.
I think I would probably use .elementIdDisplayed() to accomplish this.
The snippet below should help you
get a list of the elements
check if one is displayed
If displayed, click on the element
Usually I would use a forEach loop but since you can't break out of that without doing some hacky stuff just use a regular old for loop like this:
browser.elements('css selector', '.myClass', function(elements) {
for(let i = 0; i < elements.value.length; i++) {
browser.elementIdDisplayed(elements.value[i].ELEMENT, function(isDisplayed) {
if(isDisplayed.value) {
browser.elementIdClick(element.value[i].ELEMENT);
break; //this will break out of the loop when you find the first displayed element
}
});
}
});

Move Nth element from a div picked in an each loop

Consider the following code:
jQuery(function($)
{
$(document).ready(function()
{
$(".td-block-row").each(function()
{
var item = $(this);
$(".td-block-span4:nth-child(3)").prependTo(item.next());
});
});
});
I am trying to iterate through each .td-block-row div, and pick out the third .td-block-span4 element from it, and then move it to the next .td-block-row
The code I currently have (above) will move every Nth .td-block-span4 rather than just the one within the current div in the each loop. Essentially I am trying to do something like:
$(item ".td-block-span4:nth-child(3)").prependTo(item.next());
This may just be a case of finding out the correct syntax to make use of the item var, or perhaps I am taking a completely the wrong approach.
Any advise here would be appreciated as I have little experience with JS
The problem is you need to query td-block-span4:nth-child(3) relative to the current element(in the each handler). So
$(".td-block-span4:nth-child(3)", this).prependTo(item.next());
//or
$item.find(".td-block-span4:nth-child(3)").prependTo(item.next());

jQuery: Toggle class on one element, remove same from all other

new here and deeply hoping I'm not missing a stupid syntax flaw. I was thinking that my problem is a fairly common one, but somehow nothing has helped so far in my specific case.
There is a simple inline-block list of Image Galleries which are zoomable to fill the parent width. As soon as one is zoomed through click on a child, the others should unzoom by stripping of the class which maximizes them. Nothing more to it.
I achieved the first part via the following jQuery (where the problem is hidden in the for-loop, I think):
$(".zoom").click(function() {
var target = $(this);
target.closest('div.product-item').toggleClass('maximized');
var ot = document.getElementsByClassName('product-item');
for (var i = 0; i < ot.length; i++) {
if (ot[i] !== target) {
ot[i].removeClass('maximized');
}
}
});
So: Some .zoom classed element is clicked, its parent is toggled to maximize and a for loop checks all other elements of the same class as the parent and removes the .maximized class.
The reason the script is constructed with a for-loop and a removeClass is so that the same .zoom elements are able to minimize their parent elements, not only to maximize them.
Im not a javascript professional, but to my knowledge this should work in principle. Am I missing anything here?
This post from a year ago addressed a similar problem but didn't help in my case: jQuery onClick: How to add class to element and remove from all others
You can find a pen to see the script in action here.
$(".zoom").on('click',function() {
var target = $(this);
$('div.product-item').removeClass('maximized');
target.closest('div.product-item').toggleClass('maximized');
});
you can use
if(target.closest('div.product-item').hasClass('maximized')){
$('div.product-item').removeClass('maximized');
}else{
$('div.product-item').removeClass('maximized');
target.closest('div.product-item').addClass('maximized');
}
JSFIDDLE

how to use the closest function using specific div

I need jquery to get the closest id,once the the image is visible.
this is my query so far
(...)
if(isonscreen)
{
//this works, but I need it to find only images inside the content-bubble div tag
// and of course this grabs any image no matter what div the image is inside of
console.log($(this).closest('img').attr('id'));
}
(...)
<div class="content-bubble">
<h2>{{imageTitle}}</h2>
<img src="loading.gif" id="lazyload{{imgId}}" class="content-bubble-img"">
</div>
I've tried this but its not working and returns undefined
console.log($(this).closest('.content-bubble-img').find('img').attr('id'));
console.log($('.content-bubble-img').closest('img').attr('id'));
I thing you want the function find(), not closest().
closest finds the nearest parent of an element, while find().filter(':first') finds the first children inside an element. Or to say it with the doc's words:
closest:
For each element in the set, get the first element that matches the
selector by testing the element itself and traversing up through its
ancestors in the DOM tree.
find:
Get the descendants of each element in the current set of matched
elements, filtered by a selector, jQuery object, or element.
http://api.jquery.com/closest/
http://api.jquery.com/find/
To comment your code:
console.log($(this).closest('img').attr('id'));
This is actually pretty bad since images cant have children, this does only work since closest() returns the selected element itself which is the image when you use $(image).closest(). Replace closest with find and you're good to go.
If u have to find all images inside "content-bubble div" no matter what div the image is inside of then use this :
$('.content-bubble img');
First of all it would be much easier to fully understand what you're trying to achieve if you have added a fiddle of it.
Nevertheless I'm guessing that you're checking whether an image is currently visible - which means that in this piece of code
(...)
if(isonscreen)
{
console.log($(this).closest('img').attr('id'));
}
(...)
$(this) actually refers to the image you're interested in - thus you might want to simply retrieve its id attribute with $(this).attr('id')
Since you want to limit it to images which are placed in divs with a specific class, you might just want to check if one of its parents has class '.content-bubble', by
$(this).parents('.content-bubble').length
You may also use closest, since it actually traverses up the DOM tree from the element you specified, and:
if($(this).closest('.content-bubble').length)
which in this case would return true when $(this) or any of its parent has class .content-bubble
I'm using the espy plugin for jquery
This is how you find the id of the nearest image inside a div tag
once the image is visible
$('.content-bubble-img').espy(function (entered, state) {
if (entered)
{
// element entered the viewport
// state === 'inside'
console.log('element entered viewport');
console.log($(this).closest('img').attr('id'));
}
else
{
// element left the viewport
if (state === 'up')
{
// element is now above the trigger area
console.log('element left the viewport');
}
else if (state === 'down')
{
// element is now below the trigger area
console.log('element below the trigger area');
}
}
});

What's a good way to show parts of an element but hide the rest?

I was wanting to have a javascript (jQuery) function that removed everything that didn't have the safe class.
The problem is, if the parent element is hidden, it cannot show the 'safe' part of it.
Is there a simple way to get around this? I'd rather not go in and span all of the elements that need removed.
trimmer = function(element){
x = $(element+' *:not(.safe)');
x.hide();
}
trimmer('section');
Fiddle
var element = 'section';
//finds all non `.safe` elements in `section`s and hides them
$(':not(.safe)', element).hide();
//finds all `.safe` elements in `section`s and shows the `section`s
$('.safe', element).parents(element).show();
Horen was right, it is indeed impossible to show parts of a hidden element.
To make only parts of the text disappear, the non-safe content must be labeled for removal.
$(element).contents().each(function() {
if (this.nodeType == 3)
$(this).wrap('<span class="disappear" />');
});
You can read more about this answer here:
How to add spans to all areas of a node that isn't restricted

Categories

Resources