Okay I have list items, some have a span, some not.
On my event I want to add the span when they don't have any yet.
has()
works fine, but not()
adds the span to both??
HTML:
<ul>
<li>
<p>item</p>
<span class="spn">empty span</span>
</li>
<li>
<p>item 2</p>
</li>
<ul>
<hr>
<a class="add-span"href="#">check</a>
JS:
$("a.add-span").click(function() {
$("li").each(function(index) {
// $(this).has("span").find("span").append(" - appended");
$(this).not("span").append('<span class="spn">new span<\/span>');
})
})
You can use a combination of the :not and :has selectors like this
$("a.add-span").click(function() {
$("li:not(:has(span))").each(function(index) {
$(this).append('<span class="spn">new span<\/span>');
});
});
Here is a demo http://www.jsfiddle.net/xU6fV/
$("a.add-span").click(function() {
$("li").each(function(index) {
if ($(this).children('span').length === 0){
$(this).append('<span class="spn">new span<\/span>');
}
})
})
With children()
method, the length
property is used to check whether or not a span
already exits and if it doesn't, one is added/appended.
More Info:
- http://api.jquery.com/length/
- http://api.jquery.com/children/
The accepted answer works well, if you don't want to filter out only those elements which do have the span
s as direct children.
As the :has()
and the .has()
loop over all descendants, not just the children.
In that case, you have to use a function
$("li").not(function() {
// returns true for those elements with at least one span as child element
return $(this).children('span').length > 0
}).each(function() { /* ... */ })
Try this,
$("a.add-span").click(function() {
$("li:not(:has(span))").each(function(index) {
$(this).append($("<span class='spn'>").html("Newly Added Span"));
});
});
This is the first link on Google when searching "jquery not has". The specific scenario I needed to solve was a little different to this one. I had to not
items that have a specific DOM element, not simply based on a tag. This meant I couldn't use a selector which each solution above used.
jQuery's has()
however does accept a DOM element! So I created a jQuery plugin to combine these two inbuilt functions.
I wanted to share it here because hopefully it will help others in my situation too. It also answers the original question.
The Plugin:
(function ( $ ) {
$.fn.extend({
not_has: function (param) {
return this.not(this.has(param));
}
});
}( jQuery ));
Implementation:
$("a.add-span").click(function() {
$("li").not_has("span")
.append('<span class="spn">new span<\/span>');
// Prevent the page from navigating away
return false;
});
https://jsfiddle.net/brjkg10n/1/
I was initially intending to find a jQuery function that would work like addBack()
but using not
instead. If you need something so complicated, then please feel free to use the following plugin.
(function ( $ ) {
$.fn.extend({
notBack: function () {
return this.prevObject.not(this);
}
});
}( jQuery ));
With this, the answer would be:
$("li").has("span").notBack()
.append('<span class="spn">new span<\/span>');
https://jsfiddle.net/2g08gjj8/1/