I'm a little confused about which jQuery method and/or selectors to use when trying to select an element, and then remove certain descendant elements from the wrapped set.
For example, given the following HTML:
<div id="article">
<div id="inset">
<ul>
<li>This is bullet point #1.</li>
<li>This is bullet point #2.</li>
<li>This is bullet point #3.</li>
</ul>
</div>
<p>This is the first paragraph of the article</p>
<p>This is the second paragraph of the article</p>
<p>This is the third paragraph of the article</p>
</div>
I want to select the article:
var $article = $('#article');
but then remove <div id="inset"></div> and its descendants from the wrapped set. I tried the following:
var $article = $('#article').not('#inset');
but that didn't work, and in retrospect, I think I can see why. I also tried using remove() unsuccessfully.
What would be the correct way to do this?
Ultimately, I need to set this up in such a way that I can define a configuration array, such as:
var selectors = [
{
select: '#article',
exclude: ['#inset']
}
];
where select defines a single element that contains text content, and exclude is an optional array that defines one or more selectors to disregard text content from.
Given the final wrapped set with the excluded elements removed, I would like to be able to call jQuery's text() method to end up with the following text:
This is the first paragraph of the article.This is the second paragraph of the article.This is the third paragraph of the article.
The configuration array doesn't need to work exactly like that, but it should provide roughly equivalent configuration potential.
Thanks for any help you can provide!
I suppose you do not want to modify the original HTML by removing elements from it, but you want to just get the content of article without the inset.
Thats why I would use clone() to get a copy of the article and then remove the inset from it.
Like this:
$("#article").clone().find("#inset").remove().end().text()
$("#article") selects the article div, clone creates a
copy,
find gets the children to
remove (you could also use children),
remove(), removes the selected inset,
end() goes back to the original selection.
At the end I just added text() as you mentioned you wanted to do that.
if you want to remove anything in #article but #inset use:
$('#article > *:not(#inset)').remove() // selects all direct children of #article but not #inset and removes them
see an example here: http://jsfiddle.net/zwPsD/
if want to apply this rule to more then one DOM element you can chain them:
$('#article, #article2, #article3, #etc').find('> *').not('#inset, #that, #and. #there').remove()
you can find an example of this here:
http://jsfiddle.net/ZNjdE/
and with a simple each you can extract the text:
http://jsfiddle.net/ZNjdE/2/
Unless I am missing something, why can't you select all of the <p> elements within the article div?
$("#article p")
If that is unacceptable, I think you are looking for the filter function...
$("#article").filter(":not(#inset)")
Note: you can have multiple selectors within the :not() selector. They just have to be comma delimited, so this approach should accomodate your configurational needs.
Try something like this.
$('#article').children(':not(#inset)').each(function(){
alert($(this).text());
});
If you want to do it with an object:
var selectors = {
select: '#article',
exclude: ['#inset', 'p']
};
$(selectors.select).children(':not('+selectors.exclude.join(',')+')').each(function(){
alert($(this).text());
});
EDIT
To get any level of ancestor, you could add extra selectors and use find(). Eg.
$('#article').find('li:first, :not(#inset, #inset *)').each(function(){
alert($(this).text());
});
With this you'd be excluding #inset and all #inset's ancestors except the first li. It won't quite work with the selectors object from before though because you're excluding a group of elements and then including some of the excluded ones. You could do it with three elements in the object:
var selectors = {select: ... , exclude: ... , includeFromExcluded: ...};
Related
I have the following markup
<div class = "general">
<div id ="custom"></div>
</div>
How to change id = "custom" in all <div> with class="general" from href on page using jQuery?
You can try this:
$("div.general").each(function() {
$(this).children("div#custom").text($(this).children("a").attr("href"));
});
If I understand you correctly, you want to iterate through all div.generals, and change the text of each child div#custom to the href of the child a.
See a working example on JSfiddle.
Also, another tip is to avoid using multiple elements with the same id. In your code you have a <div> with id="custom". You also say that the div.general appears multiple times — therefore, the id "custom" will appear multiple times. This is bad practice. I suggest that you change id to class.
You need to loop through all div.general and replace the id attribute of div#custom to whatever is there as the anchors href property. The following code will work:
$(".general").each(function(){
$(this).find("#custom").attr("id", $(this).find("a").attr("href").replace("#", ""));
})
Here the .find() will dig out elements from any depth inside the parent. If you are sure about the DOM position of the elements, you can change the .find() to .children()
I need to do a function to change color (in this example) of dom element in javascript(jquery) but i have some trouble with :contains selector but i need to use because i don't have specific ID or class.
HTML :
<p id="title">John</p><!-- contain John must be red -->
<div id="description">John</div><!-- contain John must be red -->
<div id="element">
<p id="element1">John</p><!-- contain John must be red -->
<p id="element2">Anonymous</p><!-- dont contain John dont change color -->
</div>
ID in this code just to show you my problem.
Js :
$("div:contains('John'), p:contains('John')").css("color", "red");
Problem :
This script make unwanted changes (#element2)
I already check : Jquery doc but to simple dom in this example .
Testable example here : JSFIDDLE
Try to use exclude the div with other elements,
$("div:contains('John'):not(:has(*)), p:contains('John')").css("color", "red");
If your html have chances of containing elements like this,
<div id="description">John<p>test</p></div>
Then ultimately you have to go along with #TrueBlueAussie's answer.
DEMO
You could create your own filter that removes children elements and checks the textNodes of the current element only.
As the string you're trying to match is present in the comments as well, any use of innerHTML is out, so textContent is used.
$("#bug").on('click', function () {
$("div, p").filter(function() {
var clone = this.cloneNode(true);
while (clone.firstElementChild) {
clone.removeChild(clone.firstElementChild);
}
return clone.textContent.indexOf('John') != -1;
}).css("color", "red");
});
FIDDLE
Thanks for reading my post..
Just consider the below scenario of html architecture.
<div class="wrapper">
<div class="doubt-123232" id="value"></div>
<div class="question></div>
<div class="doubt-232323" id="query"></div>
</div>
In the above DOM if you need to select the class starting with doubt-***** (which include doubt-123232, doubt-232323) all at a time and do processing using jQuery.
We can select each class one by one and do processing, but in my page I have lot like this . I cant do it for each class to select and do processing then it became a trivial process.
Is there way to select the similar class or id all at time for processing in jQuery?
Thanks.
Yes, you can do this using Attribute Starts With Selector:
var divs = $('div[class^="doubt-"]');
You can use:
var items = $('div[class^=doubt]');
This is known as the "starts with" selector.
Alternatively you could use:
var items = $('div[class*=doubt]');
which is the "contains" selector.
Note that in this case, doubt is one word. If there are multiple words with spaces in between, you should put quotes around them. It is not required to quote single words.
See here for documentation on the "starts with" selector.
You can use Attribute Starts With Selector [name^="value"]
var divs = $('div[class^="doubt-"]');
selecting them all:
var doubts= $('[class^="doubt-"]');
then you access them:
doubts.each(function(index){
this. ... // and so on
});
Try somthing like this:
$("[class^=doubt-]").each(function(){ //do some staff });
For example:
<div class="mainWrapper">
<div class="FirstLayer">
<input class="foo" value="foo" />
</div>
<div class="SecondLayer">
<div class="thirdLayer">
<input class="fee" />
</div>
</div>
</div>
Lets say I have the input.fee as a jQuery object and I also need to get the value of input.foo.
Now I know I can use a multitude of approaches such as $(this).parents(':eq(2)').find('.foo') but I want to use this one method on layouts which will have varying levels and numbers of nodes.
So I am wondering if there is a method which will simply start from .fee and just keep going up until it finds the first matching element, .prevAll() does not appear to do this. There are many .foo and .fee elements and I need specifically the first one above the .fee in context.
How about this:
$('input.fee').closest(':has("input.foo")')
.find('input.foo').val();
Here's JS Fiddle to play with. )
UPDATE: Kudos to #VisioN - of course, parents:first is well replaced by closest.
This will select the previous input.foo
// self might have siblings that are input.foo so include in selection
$( $("input.fee").parentsUntil(":has(input.foo)").andSelf()
// if input.off is sibling of input.fee then nothing will
// be returned from parentsUntil. This is the only time input.fee
// will be selected by last(). Reverse makes sure self is at index 0
.get().reverse() )
// last => closest element
.last()
//fetch siblings that contain or are input.foo elements
.prevAll(":has(input.foo), input.foo")
// first is closest
.first()
// return jQuery object with all descendants
.find("*")
// include Self in case it is an input.foo element
.andSelf()
.filter("input.foo")
// return value of first matching element
.val()
jQuery.closest() takes selector and does exactly what you need - finds the first matching element that is parent of something. There's also jQuery.parents() that does take a selector to filter element ancestors. Use those combined with find method and you're set.
$('input.fee').closest('.mainWrapper").find('.foo') does the trick, doesn't it?
<div id="dad">
<img id="mum">
<input>
</div>
With jQuery, how could i get access to the input element, get is value or set it for example? I can't work out how to access something on the same level.. and i dont want to be using ID's, just parent/child nodes so i can use the code for loads of dad div's
Thanks!
an addition to Zed,
$(this).parent().children('input');
if you give a name to your input field then you can easily select throughout the others,
$(this).parent().children('input[name=my_input]');
then you can give any value as:
$(this).parent().children('input[name=my_input]').val('any value');
Sinan.
var myEl = $("#dad").children(":input");
$(this).parent().children() ?
Try this, to find the first child input element:
jQuery("div").find("input:first")
If i understand question, you would like achieve input from mum leve?
So try $("#mum ~ input")...
BTW, great site to search jquery function by category http://visualjquery.com/ +nice example.
I guess you want to find siblings (node with same depth and same parent and in DOM tree)
$(el).next() - next element (sibling) for all elements in the set
$(el).nextAll - all following siblings
$(el).nextUntil - all following siblings, stop on some condition (not including first "bad match").
Besides, you have next adjacent selector (+) and next sibling selector.
The same about prev, prevAll and prevUntil.
And you even have a siblings method.
Check this out.