How can I wrap inner divs that are dynamic? - javascript

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.

Related

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.

A Multi-Level Up Css Selector

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>

How to get to specific element in jquery

I have HTML structureL
<div class="services-article-elements-single">
<div class="services-article-description">
<button class="services-article-read-more-btn">read more</button>
</div>
<div class="services-article-after-roll"></div>
</div>
I want after clicking a button something happen with my <div class="services-article-after-roll"></div>
So far, I have:
jQuery('.services-article-read-more-btn').click(() =>{
// ????????
})
I think the appropriate method is find() but I'm not sure
Just select your element. In this case, you can select you element by class. In my simple example, the button shows or hides a div.
$('.services-article-read-more-btn').click(function() {
$(".services-article-after-roll").toggle();
})
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.9.1/jquery.min.js"></script>
<div class="services-article-elements-single">
<div class="services-article-description">
<button class="services-article-read-more-btn">My button</button>
</div>
<div class="services-article-after-roll">MY DIV</div>
</div>
EDIT: if you have a structure with more than one div with class services-article-elements-single, you can select a wrapper div using .closest() and then find the element inside that container using .find() function.
$('.services-article-read-more-btn').click(function() {
var elementWrapper = $(this).closest(".services-article-elements-single");
elementWrapper.find(".services-article-after-roll").toggle();
})
.services-article-elements-single {
padding: 10px;
margin: 10px;
border: 1px solid black;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.9.1/jquery.min.js"></script>
<div class="services-article-elements-single">
<div class="services-article-description">
<button class="services-article-read-more-btn">My button</button>
</div>
<div class="services-article-after-roll">MY DIV</div>
</div>
<div class="services-article-elements-single">
<div class="services-article-description">
<button class="services-article-read-more-btn">My button</button>
</div>
<div class="services-article-after-roll">MY DIV</div>
</div>
<div class="services-article-elements-single">
<div class="services-article-description">
<button class="services-article-read-more-btn">My button</button>
</div>
<div class="services-article-after-roll">MY DIV</div>
</div>
jQuery itself is a function which allows selecting elements. You can just use jQuery('.services-article-after-roll') and you will get the element.
jQuery('.services-article-read-more-btn').click(() => {
const $servicesArticleAfterRoll = jQuery('.services-article-after-roll');
// ... do stuff
})
Assuming you have more than one 'roll', you'll need to use a context specific selector - that just means use this within the event handler:
$(".services-article-read-more-btn").click(function() {
$(this).closest(".services-article-elements-single")
.find(".services-article-after-roll")
.fadeIn();
});
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div class="services-article-elements-single">
<div class="services-article-description">
<button class="services-article-read-more-btn">read more</button>
</div>
<div class="services-article-after-roll" style='display:none;'>more info</div>
</div>
<div class="services-article-elements-single">
<div class="services-article-description">
<button class="services-article-read-more-btn">read more</button>
</div>
<div class="services-article-after-roll" style='display:none;'>more info</div>
</div>
Where .closest finds the closest parent with that class (the containing div) and then .find goes back down within that div to find the related details.
To achieve what you require you can use DOM traversal. In the click handler you can use closest() to get the nearest common parent element to the one which raised the event and the one you want to target. Then you can use find() to get that element before amending it as required. In the example below I just toggle a class to hide/show them:
$('.services-article-read-more-btn').click(function() {
$(this).closest('.services-article-elements-single').find('.services-article-after-roll').toggleClass('show');
})
.services-article-after-roll {
display: none;
}
.services-article-after-roll.show {
display: block;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<div class="services-article-elements-single">
<div class="services-article-description">
<button class="services-article-read-more-btn">read more</button>
</div>
<div class="services-article-after-roll">After roll...</div>
</div>
<div class="services-article-elements-single">
<div class="services-article-description">
<button class="services-article-read-more-btn">read more</button>
</div>
<div class="services-article-after-roll">After roll...</div>
</div>

Hiding /Showing Div

I want the (".aboutPage") to show and hide when (".about") is clicked. On start the div is showing. How do I incorporate the hide() with this as it is not hidden once the page loads. Please help. I am aware that the div has not been sized or anything, I'll do that after I get all three working.
.aboutPage {
height: 50px;
width: 50px;
background-color: red;
}
<div class="container">
<h1 class="title">Name Goes Here</h1>
<br>
<div class="menu">
<h1 class="about">About Me</h1>
<h1 class="projects">Projects</h1>
<h1>Contact Me</h1>
</div>
<div class="aboutPage"> Here it Is</div>
</div>
You have to use toggle method in order to display or hide the matched elements.
Also, you need to bind a click event handler to .about element.
To hide div when page loads: $('.aboutPage').hide();
or using css:
.aboutPage{
display:none;
}
$('.aboutPage').hide();
$('.about').click(function(){
$('.aboutPage').toggle();
});
.aboutPage{
height: 50px;
width: 50px;
background-color: red;
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<body>
<div class="container">
<h1 class="title">Name Goes Here</h1>
<br>
<div class="menu">
<h1 class="about">About Me</h1>
<h1 class="projects">Projects</h1>
<h1>Contact Me</h1>
</div>
<div class="aboutPage"> Here it Is</div>
</div>
</body>
You can use jQuery to toggle a class that hides the element.
$('.about').on('click',function() {
$('.aboutPage').toggleClass('hide');
})
.hide {
display: none;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div class="container">
<h1 class="title">Name Goes Here</h1>
<br>
<div class="menu">
<h1 class="about">About Me</h1>
<h1 class="projects">Projects</h1>
<h1>Contact Me</h1>
</div>
<div class="aboutPage"> Here it Is</div>
</div>
And here's how you would do it in vanilla JS
document.getElementsByClassName('about')[0].addEventListener('click',function() {
document.getElementsByClassName('aboutPage')[0].classList.toggle('hide');
})
.hide {
display: none;
}
<div class="container">
<h1 class="title">Name Goes Here</h1>
<br>
<div class="menu">
<h1 class="about">About Me</h1>
<h1 class="projects">Projects</h1>
<h1>Contact Me</h1>
</div>
<div class="aboutPage"> Here it Is</div>
</div>
You certainly "can" use JQuery to do this, but it is not necessary.
See comments inline for explanation (Note: I've changed the last 3 h1 elements to p elements just so they will fit into the code snippet window here.):
// Get references to DOM objects needed to work the problem:
var a = document.querySelector(".about");
var ap = document.querySelector(".aboutPage");
// Add a "click" event handler to the .about element
a.addEventListener("click", function(){
// If .aboutPage is hidden, show it - otherwise hide it.
// Do this by adding or removing the .hide class.
if(ap.classList.contains("hide")){
ap.classList.remove("hide");
} else {
ap.classList.add("hide");
}
});
.aboutPage{
height: 50px;
width: 50px;
background-color: red;
}
.hide { display:none; }
<div class="container">
<h1 class="title">Name Goes Here</h1>
<div class="menu">
<p class="about">About Me</p>
<p class="projects">Projects</p>
<p>Contact Me</p>
</div>
<div class="aboutPage hide"> Here it Is</div>
</div>

Wrap two different elements in the same div to all classes with jQuery?

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

Categories

Resources