A Multi-Level Up Css Selector - javascript

I'm trying to find a way to use css selectors to format a specific parent div. For example, in the following sample code...
<div id="one">
<div id="two"
<div id="three">
something
...etc
I want to format div#one but only if the link inside of #one is a specific page like "foo.html".
I have tried several things but here is one example of what I have tried to use...
a[href *="foo"] #one:parent {
background-color: #FF0000;
}
Is there a way to do this using css selectors, js or jQuery? I've included a code snippet below for testing...
a[href *="foo"] #one:parent {
background-color: #FF0000;
}
<div id="one">
<div id="two"
<div id="three">
something
</div>
</div>
</div>
Everywhere I have searched for an answer has only given clues to how to do this with parent elements that are just one parent above but not several divs as in this example.

With CSS you cannot but with JS you can simply consider parentNode:
document.querySelector('a[href *="foo"]').parentNode.parentNode.parentNode.style.backgroundColor = "red";
#one {
padding:50px;
}
<div id="one">
<div id="two">
<div id="three">
something
</div>
</div>
</div>
And if you have n parent and you don't know the number you can create a loop to find your element:
var a = document.querySelector('a[href *="foo"]');
while (a.parentNode.getAttribute('id') != "one") {
a = a.parentNode;
}
a.parentNode.style.background = "red";
#one {
padding: 50px;
}
<div id="one">
<div id="two">
<div id="three">
<div>
something
</div>
</div>
</div>
</div>

Related

How to target last flex item

I have a list of divs that can be either display:none or display:flex dynamically depending on a few conditions.
How do I check, since this is dynamic, what is the last div showing display flex?
My code is something like this:
<div class="container">
<div style="display: flex"></div>
<div style="display: none"></div>
<div style="display: flex"></div>
<div style="display: none"></div>
</div>
As I say, the children might or might not be display:flex and might not necessarily be in this order or might be more items than this or not. I need to identify the last item with display:flex so I apply a borderBottom with javascript.
I need to identify the last item with display:flex so I apply a borderBottom with javascript.
Since you have js available, consider using a CSS selector targeting the display: flex:
div[style="display: flex"]
Then get the last item in the array (eg: using pop()), thats the items you're looking for.
Pure css this won't be possible.
const e = [ ...document.querySelectorAll('div[style="display: flex"]') ].pop();
e.style.border = '1px solid red';
<div class="container">
<div style="display: flex">a</div>
<div style="display: none">b</div>
<div style="display: flex">c</div>
<div style="display: none">d</div>
</div>
change your styles to a class
<div class="container">
<div class="flex">a</div>
<div class="none">b</div>
<div class="flex">c</div>
</div>
A function to get it by class name
function le(){
const container = document.querySelector(".container")
const elements = container.getElementsByClassName("flex")
return elements.item((elements.length - 1))
}
console.log(le())
and some csss
.flex {
display: flex
}
.none {
display: none
}
this is a simplest solution
$(".container").each(function() {
$('div:visible:last', this).css("background","red");
});
<!DOCTYPE html>
<html>
<head>
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
</head>
<body>
<div class="container">
<div style="display: flex">1</div>
<div style="display: none">2</div>
<div style="display: flex">3</div>
<div style="display: none">4</div>
</div>
</body>
</html>

How can I wrap inner divs that are dynamic?

I have been trying badly to wrap some divs with an outer div so that I can style them. But I'm unable to do so thus far.
I have this list div which contains some inner divs that I need to wrap. That is the inner divs which have same letters need to be bundled together. Although targeting the divs with the letters is not a good idea as they are gonna be dynamic.
This is an example of what I have been trying to achieve:
<div class="list-wrapper">
<div class="el">A</div>
<div>
<a>A</a>
</div>
</div>
<div class="list-wrapper">
<div class="el">C</div>
<div>
<a>C</a>
</div>
<div>
<a>C</a>
</div>
</div>
Another example:
This is what I have tried so far:
$(list).find('div.el').each(function(idx, item) {
$(item).nextAll('div').wrapAll('<div class="list-wrapper"></div>')
});
.wrapper {
background-color: red;
padding: 20px;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<div id="list">
<div class="el">A</div>
<div>
<a>A</a>
</div>
<div class="el">B</div>
<div>
<a>B</a>
</div>
<div class="el">C</div>
<div>
<a>C</a>
</div>
<div>
<a>C</a>
</div>
<div class="el">D</div>
<div>
<a>D</a>
</div>
<div>
<a>D</a>
</div>
<div>
<a>D</a>
</div>
<div class="el">E</div>
<div>
<a>E</a>
</div>
</div>
To achieve your goal you can use a combination of nextUntil() within the loop, to get the div elements between each .el, and wrapAll(). You can include addBack() in there to add the current .el in the loop in to the collection to be wrapped. Try this:
$('#list').find('.el').each((i, el) => {
$(el).nextUntil('.el').addBack().wrapAll('<div class="list-wrapper"></div>')
});
.wrapper {
background-color: red;
padding: 20px;
}
.list-wrapper { border: 1px solid #C00; }
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<div id="list">
<div class="el">A</div>
<div><a>A</a></div>
<div class="el">B</div>
<div><a>B</a></div>
<div class="el">C</div>
<div><a>C</a></div>
<div><a>C</a></div>
<div class="el">D</div>
<div><a>D</a></div>
<div><a>D</a></div>
<div><a>D</a></div>
<div class="el">E</div>
<div><a>E</a></div>
</div>
Note that $(list) was only working by proxy, as elements with an id attribute are available as properties on the document. It's much better practice to use a valid string selector.

QuerySelector with specified index in Javascript (like [1])

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.

Detach and append divs/html jquery

I thought this would be kinda straightforward but i cant wrap my head around this. I got to following html:
<div id="foo">
<div class="item">1</div>
<div class="item">2</div>
<div class="item">3</div>
<div class="item">4</div>
</div>
<div id="bar">
<div class="test">test1</div>
<div class="test">test2</div>
<div class="test">test3</div>
<div class="test">test4</div>
</div>
I need to grab/detach the div's .test and put/append them into the .item div's. So the first div .test needs to go in the first div .item, the second div .test to the second div .item etc. So it becomes:
<div id="foo">
<div class="item">1<div class="test">test1</div></div>
<div class="item">2<div class="test">test2</div></div>
<div class="item">3<div class="test">test3</div></div>
<div class="item">4<div class="test">test4</div></div>
</div>
Now i found some jquery code and i came to this:
var child = $('#bar').find("div").eq(0);
var parent = $('#foo').eq(0);
child.detach();
parent.append( child );
This works but as suspected, it detaches/appends the first div. Now i need to detach/append them all one by one and from reading a lot of topics, i think i need to put a loop/each in there somewhere but i have no idea how and im not getting any closer after screwing around for hours.
Anyone who can put me in the right direction with this?
You can move all of them easily by just using the append() method and selecting all the divs:
$('#bar').append( $('#foo div') )
/* This is just for showing that the elements actually moved. */
#foo { background:red; }
#bar { background:blue; }
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.11.1/jquery.min.js"></script>
<div id="foo">
<div class="item">1</div>
<div class="item">2</div>
<div class="item">3</div>
<div class="item">4</div>
</div>
<div id="bar">
<div class="test">test1</div>
<div class="test">test2</div>
<div class="test">test3</div>
<div class="test">test4</div>
</div>
<div>
Alternatively, if you want to do something with each element, you can use .each():
$('#foo div').each(function(i, elem) {
var $elem = $(elem);
//Do stuff
$('#bar').append($elem);
});
/* This is just for showing that the elements actually moved. */
#foo { background:red; }
#bar { background:blue; }
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.11.1/jquery.min.js"></script>
<div id="foo">
<div class="item">1</div>
<div class="item">2</div>
<div class="item">3</div>
<div class="item">4</div>
</div>
<div id="bar">
<div class="test">test1</div>
<div class="test">test2</div>
<div class="test">test3</div>
<div class="test">test4</div>
</div>
<div>
On solution is to get both collections and iterate over one of the collections. Also note that you don't need to use .detach. .append will already do that.
var $fooItems = $("#foo .item");
var $barTests = $("#bar .test");
$fooItems.each(function(index, el) {
$(this).append($barTests.eq(index));
});
Example Fiddle
I think there are two solutions for your issue : .childern() function or usiing jQuery selectors
For example using selector :
$("#bar > div")
or using children() function :
$("#bar").children("div");
also look at this post, you may have your answer here : jQuery - get all divs inside a div with class ".container"

jQuery/javascript - give a style to a specific element

Suppose I have 3 page as below:
page 1:
<div id="content">
<div id="red"></div>
</div>
page 2:
<div id="content">
<div id="blue"></div>
</div>
page 3:
<div id="content">
<div id="green"></div>
</div>
This 3 page are in the same template, so if I add
#content {
margin-top: 10px;
}
All page will apply this style, If I only want to put this style to page 3, how can I do that?
Generally, we use $('#content > #green').css(...) to point to a element, but can we have something like $('#content < #green') to point to a reversed element and give it some style?
You can use:
$('#green').parent().css(...);
If you want to be completely specific, you can do:
$('#green').parent('#content').css(...);
Or you could create a new style class 'contentClass' which holds the styles for elements with id="content" and apply the style class to red, green, and blue. In this way, content becomes an abstract container with no styles, and the actual styling gets moved where it should.
So in your style sheet:
.contentClass {
/* Your content styles here /*
}
And on your pages:
<div id="content">
<div id="red" class="contentClass"></div>
</div>
<div id="content">
<div id="green" class="contentClass"></div>
</div>
<div id="content">
<div id="blue" class="contentClass"></div>
</div>
Have you tried $("#content eq(index of element)") ??

Categories

Resources