I have the below code to find the index of li have the class active
and do not have hidden
class. In order to find the value we don't want to count hidden
class.
var index = $('li').not('.hidden').find('.active').index();
alert(index)
<script src=".1.1/jquery.min.js"></script>
<ul>
<li class="hidden">.....</li>
<li>....</li>
<li class="hidden">....</li>
<li class="active">....</li>
<li>....</li>
<li class="hidden">....</li>
<li>....</li>
</ul>
I have the below code to find the index of li have the class active
and do not have hidden
class. In order to find the value we don't want to count hidden
class.
var index = $('li').not('.hidden').find('.active').index();
alert(index)
<script src="https://ajax.googleapis./ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<ul>
<li class="hidden">.....</li>
<li>....</li>
<li class="hidden">....</li>
<li class="active">....</li>
<li>....</li>
<li class="hidden">....</li>
<li>....</li>
</ul>
Here I got result -1.but my expected result is 1.is it possible to find this?
Share Improve this question edited May 2, 2016 at 11:02 Praveen Kumar Purushothaman 167k27 gold badges213 silver badges260 bronze badges asked May 2, 2016 at 11:00 Shijin TRShijin TR 7,78811 gold badges63 silver badges125 bronze badges 2- What are you trying to count exactly? – PinkTurtle Commented May 2, 2016 at 11:13
- Position of .active ,exclude .hidden – Shijin TR Commented May 2, 2016 at 11:14
3 Answers
Reset to default 8You can use .filter()
, it searches in same level i.e. a subset of the matching elements where as .find()
looks in descendant elements
var index = $('li').not('.hidden').filter('.active').index();
OR, It can be improved as
var index = $('li.active:not(.hidden)').index();
If you need to exclude .hidden
, then you need to remove them from the unordered list then .index()
can be used.
var index = $('ul').clone().find('li.hidden').remove().end().find('li.active').index();
var index = $('ul').clone().find('.hidden').remove().end().find('li.active').index();
console.log(index)
<script src="https://ajax.googleapis./ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<ul>
<li class="hidden">hidden</li>
<li>....</li>
<li class="hidden">hidden</li>
<li class="active">active</li>
<li>....</li>
<li class="hidden">hidden</li>
<li>....</li>
</ul>
While you've already accepted another answer at the time of writing, I thought I'd offer an alternative approach, using plain JavaScript, to do the same (albeit with the options for further, simple, customisation):
// using a named function allows you to call that function
// repeatedly in response to interaction or other events:
function findIndexOf(opts) {
// setting the 'default' settings of the function,
// these defaults can be overridden by the user:
// 'needle': String, the class-name of the element(s)
// whose index/indices you wish to find.
// 'haystack': String, the CSS selector for those elements
// from which you expect to find the 'needle(s).'
// 'disregard': String, the class-name of those elements in
// the haystack you wish to disregard from the
// index 'count.'
// 'firstIndexOnly' : Boolean, true - return only the index of the
// first needle found;
// false - return the indices of all
// found needles.
let settings = {
'needle': 'active',
'haystack': 'ul li',
'disregard': 'hidden',
'firstIndexOnly': true
};
// Using Array.prototype.forEach() to iterate over the
// array of keys returned from Object.keys, of either
// the 'opts' Object (supplied by the user to override
// the default settings), or an empty Object to prevent
// errors being thrown if the opts Object doesn't exist:
Object.keys(opts || {}).forEach(function(key) {
// 'key' is supplied the anonymous function,
// and refers to the current key of the array
// over which we're iterating.
// here we update the settings[key] with the value of
// opts[key]:
settings[key] = opts[key];
});
// Using Array.from() to convert the NodeList returned by
// document.querySelectorAll( settings.haystack ) into an
// Array, in order to employ Array methods on that collection:
let lis = Array.from(document.querySelectorAll(settings.haystack)),
// here we use Array.prototype.filter(), with an Arrow
// function syntax, to retain only those elements
// whose classList does not contain the class identified
// by the settings.disregard option, thereby removing the
// options to be disregarded from the collection:
notDisregarded = lis.filter(el => el.classList.contains(settings.disregard) === false),
// iterating over the NotHiddenLis Array with
// Array.prototype.map(), to obtain the indices of
// those elements matching the class-name supplied
// by the settings.needle option:
indices = notDisregarded.map(function(el, index) {
// Again, the arguments here are supplied by the
// anonymous function though the names are chosen
// by the user, the first argument (here 'el')
// is the array element of the Array over which
// we're iterating; 'index' (the second argument)
// is the index of that current array element.
// element.classList.contains() returns a Boolean
// true, if the class-name supplied is found within
// the classList of the element; or false if it is
// not found.
if (el.classList.contains(settings.needle)) {
// if the element has the supplied class-name
// (the string held in the settings.needle variable)
// el.classList.contains() evaluates to true, and then
// we return the associated index:
return index;
}
// because the above approach returns undefined (when the
// element.classList.contains() returns false) we here use
// Array.prototype.filter(), with an Arrow function, to
// retain only those array-elements that hold a value:
}).filter(value => value);
// to ensure we behave similarly to Array.prototype.indexOf(),
// and String.prototype.indexOf(), we check the length of
// the array of found indices and, if no elements were found,
// and therefore no indices were retained, we push the value of
// -1 into the array:
if (indices.length === 0) {
indices.push(-1);
}
// if the the settings.firstIndexOnly option is set to true,
// we return an array consisting of only the first array-element
// from the indices array, otherwise we return the whole array
// (whether that array contains only one value or multiple).
// We wrap the first array-value within an array in order to
// provide consistency in the returned values, so that the
// function always returns an Array:
return settings.firstIndexOnly === true ? [indices[0]] : indices;
}
// Almost entirely irrelevant, this is just to tidy the
// console/snippet output:
let found = findIndexOf(),
prepend = found.length === 1 ? 'Index: ' : 'Indices: ';
// showing the output of the function in the snippet.log
// (with thanks to T.J. Crowder):
snippet.log(prepend + JSON.stringify(found) );
function findIndexOf(opts) {
let settings = {
'needle': 'active',
'haystack': 'ul li',
'disregard': 'hidden',
'firstIndexOnly': true
};
Object.keys(opts || {}).forEach(function(key) {
settings[key] = opts[key];
});
let lis = Array.from(document.querySelectorAll(settings.haystack)),
notDisregarded = lis.filter(el => el.classList.contains(settings.disregard) === false),
indices = notDisregarded.map(function(el, index) {
if (el.classList.contains(settings.needle)) {
return index;
}
}).filter(value => value);
if (indices.length === 0) {
indices.push(-1);
}
return settings.firstIndexOnly === true ? [indices[0]] : indices;
}
let found = findIndexOf(),
prepend = found.length === 1 ? 'Index: ' : 'Indices: ';
snippet.log(prepend + JSON.stringify(found) );
li {
height: 2em;
line-height: 2em;
border: 1px solid currentcolor;
margin: 0 0 0.5em 0;
list-style-type: none;
}
.hidden {
color: #f90;
width: 80%;
opacity: 0.6;
}
.active {
color: limegreen;
width: 50%;
}
li::before {
content: attr(class);
display: inline-block;
text-indent: 1em;
}
<!-- Provides the `snippet` object, see https://meta.stackexchange./a/242144/134069 -->
<script src="https://tjcrowder.github.io/simple-snippets-console/snippet.js"></script>
<ul>
<li class="hidden">.....</li>
<li>....</li>
<li class="active">....</li>
<li class="hidden">....</li>
<li>....</li>
<li class="hidden">....</li>
<li class="active">....</li>
</ul>
JS Fiddle demo.
As a potential, but unlikely-to-be-relevant, alternative (depending entirely on your use-case) you could do something similar with CSS alone, albeit it's worth noting explicitly that this approach can only style the elements, albeit content can be added using CSS generated content and pseudo-elements (again, I don't think this is what you want, but I'm not certain, and it may be of use to others in future):
li {
height: 2em;
line-height: 2em;
border: 1px solid currentcolor;
margin: 0 0 0.5em 0;
list-style-type: none;
}
.hidden {
color: #f90;
width: 80%;
opacity: 0.6;
}
.active {
color: limegreen;
width: 50%;
}
li::before {
content: attr(class);
display: inline-block;
text-indent: 1em;
}
/* Selecting those <li> elements that do
not have the 'hidden' class-name: */
li:not(.hidden) {
/* defining a counter to increment
each time an matching element is found: */
counter-increment: liActive;
}
/* Selecting those <li> elements with the class
of 'active' that do not have the class of
'hidden', and defining a pseudo-element for
those elements: */
li:not(.hidden).active::after {
/* Setting up some content to be shown, in this
case the string of 'Index: ' concatenated
with the output of the CSS counter function: */
content: 'Index: ' counter(liActive);
color: red;
float: right;
}
<ul>
<li class="hidden">.....</li>
<li>....</li>
<li class="active">....</li>
<li class="hidden">....</li>
<li>....</li>
<li class="hidden">....</li>
<li class="active">....</li>
</ul>
JS Fiddle demo.
References:
- CSS:
counter-increment
.- CSS pseudo-elements.
- Negation (
:not()
) pseudo-class. - "Using CSS counters."
- JavaScript:
Array.from()
.Array.prototype.filter()
.Array.prototype.forEach()
.Array.prototype.map()
.Array.prototype.push()
.- Arrow function syntax.
document.querySelector()
.document.querySelectorAll()
.Element.classList
API.JSON.stringify
.let
statement.Object.keys()
.
Tools:
snippet.js
, created by T.J Crowder, found at: https://meta.stackexchange./a/242144/130770
Instead of li use ul
var index = $('ul').not('.hidden').find('.active').index();
alert(index)