Can anyone explain this bizarre behavior in jQuery next? - javascript

It works:
<div class="xpav">
Create
</div>
<div class="apr" style="display: none;">
sometext
</div>
<script>
$('.xpav').click(function() {
$(this).next(".apr").slideDown("fast");
})
</script>
It doesn't:
<div class="xpav">
Create
</div>
<br />
<div class="apr" style="display: none;">
sometext
</div>
<script>
$('.xpav').click(function() {
$(this).next(".apr").slideDown("fast");
})
</script>
Why breaks it?

.next() only looks at the element that comes after the given element, then checks that element against the selector if it's provided. In your second example, since the br is there and doesn't have the apr class, it isn't picked up. From the API docs:
Description: Get the immediately following sibling of each element in the set of matched elements. If a selector is provided, it retrieves the next sibling only if it matches that selector.
Your second example requires the use of .nextAll() instead to search through all the next siblings:
$('.xpav').click(function() {
$(this).nextAll(".apr").slideDown("fast");
});
To pick up only the first .apr that's matched, use .eq(0):
$('.xpav').click(function() {
$(this).nextAll(".apr").eq(0).slideDown("fast");
});

under my impression next() only works if the sibling objuect is the same DOM tage,
what does work is:
$('.xpav').click(function() {
console.log($(this).next(".apr"));
$(this).siblings(".apr").slideDown("fast");
})

It's exactly that what the documentations says: "Description: Get the immediately following sibling of each element in the set of matched elements. If a selector is provided, it retrieves the next sibling only if it matches that selector."
http://api.jquery.com/next/

Because next() takes you to the immediate next DOM element which is <br />. Why not use this:
$(".apr").slideDown("fast");

Simply because you are using the next() method in your code. The next DOM element from $('.xpav') in the second version of your code is a <br />, and since that doesn't match the filter, it doesn't slide anything down!
If you want it to work, you should consider using nextAll() instead of next(), as the latter ONLY gets the very next DOM element, where the former gets all siblings that are after itself in the DOM.

Related

jQuery - how to find element inside following child?

I need the jQuery statement to find ".findme" in this code:
$('.clicky').click(function() {
// the .find() method doesn't do it
$(this).find('.findme').css('color', 'red');
});
<div class='clicky'></div>
<div class='brother'>
<div class='findme'>Here I am</div>
</div>
I've tried variations on .find() and .next() and .children() and I can't quite work it out....
this in $(this).find('.findme') actually refers to the element that was clicked (the div with the class clicky.
.find() actually searches the descendants of the element you call it on, and since "findme" is not within the "clicky" div, it doesn't find it.
You should instead use jquery's .next() function to get the sibling immediately following the "clicky" div (that's the "brother"), and then search there for the "findme" div.
$(this).next().find(".findme").css("color", "red");
you may can try to change
$('.clicky').click(function() {
// the .find() method doesn't do it
$(this).siblings().children('.findme').css('color', 'red');
});
and i think you miss the click me inner text for the div
<div class='clicky'>click me!!!</div>
<div class='brother'>
<div class='findme'>Here I am</div>
</div>

Jquery select previous element with class

I have 3 elements:
<div class='first'>First</div>
<div class='second'>Second</div>
<div class='target'>Target</div>
on click on target div I test .prev() function in my js
$(document).on('click','.target',function(){
console.log($(this).prev().html());
console.log($(this).prev('.first').html());
});
Output is like: 'Second undefined', but should be like: 'second first' if I understand right the parameter of .prev() usage.
How can I get first previous element with certain class then?
Here is fiddle for you: http://jsfiddle.net/0fzgzce5/
From jQuery docs,
.prev()
Description: Get the immediately preceding sibling of each element in
the set of matched elements, optionally filtered by a selector.
To select all preceding sibling elements, rather than just the
preceding adjacent sibling, use the .prevAll() method.
http://api.jquery.com/prevAll/
So you should use console.log($(this).prevAll('.first').html());
You can make use of sibling() which will return the element with specific class and at same level as calling elment. But make sure that there is no same div after target
$(document).on('click','.target',function(){
console.log($(this).siblings('.second').html());
console.log($(this).siblings('.first').html());
});
DEMO
OR you can use prevAll()
$(document).on('click','.target',function(){
console.log($(this).prevAll('.second').html());
console.log($(this).prevAll('.first').html());
});
DEMO
Use prevAll() instead of prev()
$(document).on('click', '.target', function() {
alert($(this).prevAll('.second').html());
alert($(this).prevAll('.first').html());
});
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div class='first'>First</div>
<div class='second'>Second</div>
<div class='target'>Target</div>
You can use also $("div:eq(3)") to get the exact element. Best example is $("ul li:eq(3)")
In your second console.log(), yous this is still .target and it does not have .first class so it is saying undefined.
To get the first dive, do:
console.log($(this).prev().prev().html());
Jquery .prev() always get immediate preceding sibling.
if you pass a selector as parameter it will filter the preceding element to match with, if it did not match it will return undefined, in your case this is happening
$('.target').prev().html()
is same as
$('.target').prev('.second').html();
which will return "Second"
If you pass any selector other than '.second' it alway return undefined so, your case
$('.target').prev('.first').html();
is as exprected, returning undefined because '.first' is not matching with preceding element selector.
Update:
if you want to get First the use
$('.target').prev().prev().html();

Is there a method in jQuery that will traverse up the dom tree from an element and check selectors before its parent element

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?

jquery remove removing from another element

According to here, jquery's remove function should work like so..
$('div').remove('selector');
Which I'm trying in this example.
HTML:
<div class="wrapper">
<p class="unwanted">This should be removed</p>
<p class="retained">This will remain</p>
</div>​
JavaScript:
jQuery(document).ready(function($) {
$('div').remove('p.unwanted'); //not working
//$('p.unwanted').remove(); //this works
});
​
It's not working. What am I doing wrong?
You've misunderstood what the documentation is saying. It's not looking for elements that are descendants of the matched elements that match the selector, it's simply filtering down the set of already matched elements to those that match the selector, and then removing them.
If you have this HTML:
<div class="wanted">Some text</div>
<div class="wanted">Some more text</div>
<div class="unwanted">Some unwanted text</div>
and then executed this jQuery:
$('div').remove('.unwanted');
then it would only remove that third <div> (the one with the unwanted class on it), because it first selects all <div> elements, and then only removes those that match the selector.
Example jsFiddle
You're trying to remove something that is both div and p.unwanted. The filter in remove() is applied to the current set of nodes, which in this case is all div elements.
Use the children set instead:
$('div').children().remove('p.unwanted');
You should use the following:
$('p').remove('.unwanted');
Argument in remove works as a filter. So here, you first select all <p> elements and then remove only those which have class unwanted.
DEMO: http://jsfiddle.net/qwXSw/1/
try this
$(document).ready(function() {
$('div').find('p.unwanted').attr('class', '');
});

How to remove prev . prev object? Javascript .prev().remove();

It's like
<input name="fails[]" type="file" size=40 /><br />
<textarea name="apraksts[]">About</textarea>
<a href="#" onclick="remove(this);return false".....>remove</a>
And the javascript:
function remove(obj){
$(obj).prev('textarea').remove();
$(obj).prev('input').remove();
$(obj).remove();
}
Why it doesnt remove INPUT(why it doesnt remove two objects)?
Thanks..
The documentation for prev says it:
Get the immediately preceding sibling of each element in the set of matched elements, optionally filtered by a selector.
After you remove the <textarea>, that element is a <br>. Since it doesn't match input, the resulting jQuery object contains no elements. You then remove those 0 objects.
I suspect a better approach to the problem would be to wrap all the elements in a <div> (or a container with more suitable semantics for the context) and remove that (instead of removing each element in turn).
Or you can also use prevAll. That will select all previous sibling elements which are then filtered by your selector:
$(obj).prevAll('input').remove();

Categories