Is there any way to select all elements from given elements to another given elements?
example:
<div>
<div>
<a name="break1"></a>
<p> belongs to break 1</p>
<div>
<p> belongs to break 1</p>
</div>
</div>
<p>belongs to break 1</p>
<div>
<a name="break2"></a>
<p> belongs to break 2</p>
<div>
<p> belongs to break 2</p>
<div>
<p> belongs to break 2</p>
</div>
</div>
</div>
</div>
we need something like the following:
$('[name*="break1"]').selectAllUntil('[name*="break2"]');
and result should be:
<p> belongs to break 1</p>
<div>
<p> belongs to break 1</p>
</div>
<p>belongs to break 1</p>
Most important thing: need to look down the siblings of each element up to the element matched by the selector, if we didnt find it we need to keep searching at the parent node
this can be misleading because we need to select all until the next element, even though the next element exist in the parent elements
Assuming the html is always the same you could try using prevAll().
Example:
$('.break2').parent().prevAll().css('color', 'blue');
https://jsfiddle.net/kt10r6n5/1/
Note:
If you are using a class like you have in your demo then this might be problematic if you have multiple instances of that same class. You would then have to find the last instance of that class. This will work better with an id of course.
Docs:
http://api.jquery.com/prevall/
I created method in plunker:
https://plnkr.co/edit/XUNCkYMJz4TEekLdBrJM?p=preview
This script returns jquery object with collection of elements between selector1 and selector2.
EDIT. Ok i got in now! It should work as expected.
IMPORTANT - script is working on level of selector parent, so is dependend to html structure.
jQuery.fn.extend({
selectAllUntil: function(selector) {
var currentDiv=this.parent("div");
var elements = $();//empty jquery collection
while(currentDiv.length){
if (currentDiv.find(selector).length){
//if our element have inside selector then this is end
return elements;
}else{
//no selector so add
elements= elements.add(currentDiv);
}
//next element
currentDiv=currentDiv.next();
}
}});
//usage:
$(function(){
var elements=$('[name*="break2"]').selectAllUntil('[name*="break4"]');
elements.css("color","red");
});
Related
I have an HTML structure with three structures of some element and two p's right under:
<some_tag></some_tag>
<p></p>
<p></p>
<some_tag></some_tag>
<p></p>
<p></p>
<some_tag></some_tag>
<p></p>
<p></p>
In practice I have much more than just three structures (more like thirty) so I need automation.
I need to select each last p in the first two structures, but not the last p in the last structure.
My problem
There seem to be no CSS way to do the selection I desire.
Considering an HTML way of wrapping each non-last, some_tag structure in some other element (like a div) I conclude I don't like this solution as it seems to me unaesthetic.
My question
Do you know a way to automate the described selection via JavaScript?
This is not a good HTML structure for what you want to do. It will be much easier if you wrap each set of hX and p inside a container tag like a div.
Otherwise you are going to have to loop over each element with JavaScript and decide whether to apply styles (if the current element is a p, and there is a next element, and it's not a p).
You can do this with JavaScript, here is an example:
const elements = document.querySelectorAll("*");
let latestParagraph;
const paragraphsToStyle = [];
for(const element of elements){
if(element.tagName === "P"){
latestParagraph = element;
}else{
if(latestParagraph){
paragraphsToStyle.push(latestParagraph);
}
}
}
paragraphsToStyle.pop();
for(const paragraph of paragraphsToStyle){
paragraph.style.color = "red";
}
<h3>h</h2>
<p>p1</p>
<p>p2</p>
<h2>h</h2>
<p>p3</p>
<p>p4</p>
<h1>h</h2>
<p>p5</p>
<p>p6</p>
This will only work if there is no nesting.
The script runs through all the elements on the page and when a non paragraph element is encountered, it adds the latest paragraph found to the paragraphsToStyle array. At the end of the first loop, the last paragraph on the page is removed from the array paragraphsToStyle.pop()
Is your layout created dynamically? You could always use css classes to handle this easily. If you are not able to control this with layout here is a quick way to do it:
#myLayout *:not(:last-child) > p:last-child {
color: red
}
This code grabs every parent with a p child. It should ignore the last child sibling and always grab the last p. I would recommend replacing the * with a node or a css selector though to prevent unexpected results. I also recommend at least limiting possible issues by enclosing everything in a container like below.
<div id="myLayout">
<div>
<h2>h1</h2>
<p>p1</p>
<p>p2</p>
</div>
<div>
<h2>h1</h2>
<p>p1</p>
<p>p2</p>
</div>
<div>
<h2>h1</h2>
<p>p1</p>
<p>p2</p>
</div>
</div>
Edit: As others have mentioned, you may want to restructure your HTML so that it can work with selectors more easily. But if that's not possible, you can use JavaScript for this. In this case, all you have to do is see if the element is a 'p' tag and if the next element is not a 'p' tag:
var children = document.getElementById('content').children;
for (let i = 0; i < children.length - 1; i++) {
let nextTagName = children[i+1].tagName;
if (children[i].tagName === 'P' && nextTagName !=='P') {
children[i].classList.add('selected');
}
}
.selected {
color: aqua;
}
<div id="content">
<h2>Heading 1</h2>
<p>p 1</p>
<p>p 2</p>
<h3>Heading 2</h3>
<p>p 3</p>
<p>p 4</p>
<h4>Heading 3</h4>
<p>p 5</p>
<p>p 6</p>
</div>
I am looking for a certain word, for instance "unique" on the current webpage to remove the content of the directly surrounding tag, but not more.
Example
<div>
<div>test unique is
</div>
</div>
<p>Hello
</p>
becomes
<div>
<div>
</div>
</div>
<p>Hello
</p>
Iow, innerText or innerHTML of the containing tag is set to ''.
So far, I did
<script>
var badDivs = $("div:contains('unique')");
badDivs.remove ();
</script>
but I want to
include all tags, not just div
only want the upmost tag to be set to '', not the whole page be blank because somewhere nested there is the word unique.
It should work with tags that have or don't have attributes as in the example
It appears as though you don't want to remove the tag, only its contents Since the selector *:contains('unique') selects every element, including the parents, you'll want to grab the last element selected.. See find, last, and empty.
$(function() {
$(document).find(":contains('unique')").not("script").last().empty();
});
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div>
<div>test unique is
</div>
</div>
<p>Hello
</p>
In the case of this Stack Snippet, the script in inserted into the body element in the iframe, so I've specifically excluded those elements.
Filter elements that contain the text but don't have any other children.
$(':contains("unique")').filter(function(){
return !$(this).children().length;
}).empty()
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div>
<div>test unique is
</div>
</div>
<p>Hello
</p>
I am looking for a way to find the first direct child of an element, of a precise type.
Let's imagine this markup:
<div id="mainDiv">
<div id="otherDiv">
<p> Stuff </p>
</div>
<p> Stuff 2 </p>
<p> Stuff 3 </p>
</div>
So here, what I want to get is "Stuff 2" the first paragraph to be a direct child.
If using jquery I do something like $('#mainDiv').find('p:first'); I will get the paragraph inside the first div.
What I need is to ignore nested childs and take only the first direct one. How should I do that?
Use the direct descendant selector >
$('#mainDiv > p:first')
or even children()
$('#mainDiv').children('p').first()
I'm binding the following function to a toggle button I have created to hide/unhide content that is located bellow the button, but on an other level in the DOM.
var togglelabel = packagehead.append("<div>").children().last().addClass("togglewrap").append("<label>")
.children().last().addClass("toggle android header-toggle")
.on('click', function(){
$(this).parent().parent().next('.hidable').toggle();
});
The html structure looks like this:
<div>
<div class="packageheader">
<span>Package #1501</span>
<div class="togglewrap">
<label class="toggle android header-toggle">
<input type="checkbox">
<p>
<span>More</span>
<span>Less</span>
</p>
<a class="slide-button">
</a>
</label>
</div>
</div>
<br>
<p class="hidable">
<pre>content here</pre>
</p>
</div>
This code doesn't work to hide the <p> with the class .hidable.
I've tried 'debugging' the code using console.log() to see what element 'this' represents and found that it does, as expected, represent the label element.
So I thought that using the following chain:
$(this).parent().parent().next('.hidable').toggle();
Would correctly go 2 levels up to the <div class="packageheader"> and then take the next sibling with the class hidable, which would be <p class="hidable">
Here is a screenshot of the structure, to be sure I didn't miss anything:
You can do this :
$(this).closest('.packageheader').nextAll('.hidable').first().toggle();
Note that it's slightly preferable to use closest instead of parent().parent() as it won't break as easily when the HTML changes and it's easier for the maintainer to decipher what the code does.
Note also that your HTML is invalid, you can't have a PRE inside a P.
Demonstration
I am looking for a Javascript solution for this problem. I have the following HTML:
<div id = "container">
<div id = "data">
<div>
<h3> Address</h3>
<b>Expand...</b>
<div id="content">ul. Pomorska</div>
</div>
<div>
<h3> Telefon </h3> <b>Expand...</b>
<div id="content">26565352</div>
</div>
<div>
<h3>Email</h3>
<b>Expand...</b>
<div id="content">asdasdag#aga.com</div>
</div>
</div>
</div>
I would like to hide the content div when an onclick Expand is made. So far I have made a function which hides the content divs and tries to assign an event handler to the node.
function hideinfo() {
var node = document.getElementById("data");
var contactdata = node.getElementsByTagName("div");
for(var i=0; i<contactdata.length;i++) {
if(contactdata[i].id == "content") {
alert(contactdata[i].previousSibling.innerHTML);
contactdata[i].previousSibling.addEventListener('click',ShowHide,false);
contactdata[i].style.display="none";
}
}
}
The problem is that the alert displays undefined. Why can't it see the node? Is there a better way to do this in Javascript?
Because previousSibling is most likely the text node before the div element. You probably want to use previousElementSibling instead :)
In most browser today, querySelectorAll, which lets you use CSS selectors for finding elements, is also a good alternative (IE8+)
The previousSibling property returns the previous sibling node (the previous node in the same tree level) of the selected element
which returns in your case the TEXT node.
As you can see in this jsfiddle: http://jsfiddle.net/Xu383/
alert(contactdata[i].previousSibling.nodeName);
You are better of using the querySelectorAll.
Also you can't have multiple divs with the SAME id, use class instead.