Determine the .length index of the <li> item clicked [duplicate] - javascript

This question already has answers here:
Get index of clicked element using pure javascript
(10 answers)
Closed 9 years ago.
I have a set of <li> items:
<ul id="listings">
<li id="item-0">
<div class="content">hi</div>
<li>
<li id="item-1">
<div class="content">hi</div>
<li>
<li id="item-2">
<div class="content">hi</div>
<li>
</ul>
//etc
My question is: How do I determine the index number of the clicked <li> item?.
Like if I click: <li id="item-1"> I want to know it's the second <li> index.
I can easily determine the total lenght of all <li>'s by doing:
document.querySelectorAll('#listings li').length;
And I currently have the following click listener:
document.getElementById("listings").addEventListener("click", function(e) {
if(e.target && e.target.nodeName == "LI") {
console.log(e.target.id + " was clicked");
}
});

<ul id="listings">
<li id="item-0" onclick="isClicked(0)">
<div class="content">hi</div>
</li>
<li id="item-1" onclick="isClicked(1)">
<div class="content">hi</div>
</li>
<li id="item-2" onclick="isClicked(2)">
<div class="content">hi</div>
</li>
//...
I would add an onclick function to the li. Using javascript you can collect the data.
function isClicked(number){
alert("Clicked element: "+ number);
}

var ulLength = document.getElementById('listings');
var elements = [].slice.call(ulLength.childNodes);
//[].slice.call() is used to convert array-like objects/collections into an array
function getSiblings() {
var _s = [];
elements.forEach(function (i, d) {
if (i.nodeType === 1) //prevents text nodes to be counted as siblings
_s.push(i);
});
return _s;
}
function getElmIndex(elm) {
var _siblings = getSiblings();
for (var i = 0; i < _siblings.length; i++) {
if (!(_siblings[i] && _siblings[i] !== elm)) {
return i;
}
}
}
elements.forEach(function (elm, d) {
elm.addEventListener("click", function (e) {
var _index = getElmIndex(this);
alert("Index: " + _index);
});
});
Fiddle Link

If using Jquery is not a problem, I suggest the use of the index() method: http://jsfiddle.net/JLkPs/ .
Source: http://api.jquery.com/index/

Related

jQuery - Sort list into groups with headings, then alphabetically

I'm trying to sort a list into groups with headings in alphabetical order. So far I found a solution of the first step here: Use jQuery to sort a list into groups with headings
Then I want the headings to be sorted alphabetically. The nested lists should be sorted alphabetically so that it goes from this:
<ul id="list">
<li class="grouphead">Meat</li>
<li>
<ul>
<li>Lamb</li>
<li>Pork</li>
<li>Beef</li>
</ul>
</li>
<li class="grouphead">Fruit and Vegetables</li>
<li>
<ul>
<li>Orange</li>
<li>Banana</li>
<li>Cabbage</li>
</ul>
</li>
</ul>
to this
<ul id="list">
<li class="grouphead">Fruit and Vegetables</li>
<li>
<ul>
<li>Banana</li>
<li>Cabbage</li>
<li>Orange</li>
</ul>
</li>
<li class="grouphead">Meat</li>
<li>
<ul>
<li>Beef</li>
<li>Lamb</li>
<li>Pork</li>
</ul>
</li>
</ul>
Here's what I have so far: http://jsfiddle.net/z6j5t0k3/5/
<ul id="list">
<li>Lamb</li>
<li>Pork</li>
<li>Beef</li>
<li>Banana</li>
<li>Orange</li>
<li>Cabbage</li>
</ul>
var dict = {
}
$("#list li").each( function() {
var k = $(this).children(":first").attr('rel');
if ( dict.hasOwnProperty(k) == false ) {
dict[k] = [];
}
dict[k].push( $(this).html() );
} );
$("#list").empty();
function newList(nam) {
var r = "";
for ( c in dict[nam] ) {
r += "<li>" + dict[nam][c] + "</li>";
}
return r;
}
for ( nam in dict ) {
$("#list").append("<li class='grouphead'>" + nam + "</li>");
$("#list").append("<li><ul>" + newList(nam) + "</ul></li>");
}
function uCase(elem) {
return $.trim( $(elem).text().toUpperCase() )
}
function compareFirstLink(a, b) {
var A = uCase( $(a).first('a') ),
B = uCase( $(b).first('a') );
return (A > B) ? 1 : -1;
}
$(function () {
var $sortables = $("ul:has(div:first-child), li:not(.fixedOrder)");
$sortables.sort(compareFirstLink).each(function () {
this.parentNode.appendChild(this);
});
});
I used the code from this (Sorting nested lists) to try to sort the nested lists alphabetically but it didn't work.
Thank you!

how to apply active class using ng-class for list elements(mutli-select)?

I have a scenario,that I have static list elements,where I need to add active class using ng-class,when I click on list element,the active class would be added.
Here is my code:
vm.idArry = [];
vm.selectedFunc = function (item) {
item.selected = !item.selected;
if(vm.idArry.indexOf(item) == -1){
vm.idArry.push(item);
}
else {
var index = vm.idArry.indexOf(item);
vm.idArry.splice(index, 1);
}
}
Html:
<ul>
<li id="one"><a ng-class="{'active':item.selected}" ng-click="selectedrFunc(1)" ></a></li>
<li id="two"><a ng-class="{'active':item.selected}" ng-click="selectedFunc(2)" ></a></li>
<li id="three"><a ng-class="{'active':item.selected}" ng-click="selectedFunc(3)"></a></li>
<li id="four"><a ng-class="{'active':item.selected}" ng-click="selectedFunc(4)" ></a></li>
<li id="five"><a ng-class="{'active':item.selected}" ng-click="selectedFunc(5)"></a></li>
<li id="six"><a ng-class="{'active':item.selected}" ng-click="selectedFunc(6)" ></a></li>
for the above code,I have to get append active class when I click on list elements(i.e; multiple list must be added active class when I clicked on multiple list elements).
Thanks in advance.
Any help would be appreciated.
Remove usage of item.selected and use following code:
<li id="one"><a ng-class="{'active': vm.idArry.indexOf(1) != -1}" ng-click="selectedFunc(1)" >A</a></li>
This checks for item existence in vm.idArray; Also remove item.selected on vm.selectedFunc
So your vm.selectedFunc should look like this:
vm.selectedFunc = function (item) {
if(vm.idArry.indexOf(item) == -1){
vm.idArry.push(item);
}
else {
var index = vm.idArry.indexOf(item);
vm.idArry.splice(index, 1);
}
}

Losing context in callback when invoked the second time backbone

The following code works, but I think there's room for improvement. The index check is there because after the first element is removed the next element looks like it has an index of -1, but is actually the previously removed element. Then it iterates again and finds the clicked element and removes it. BUT since the index is -1 on the first go around the wrong group gets deleted.
How do I keep the zombie elements from being iterated on more efficiently? This is in a backbone view with an in page confirmation.Thanks.
EDIT: To add HTML
Group section always has a default group that shouldn't be deleted.
<div class="section-border-top--grey js-favorite-group">
<h4 class="expandable__cta cta--std-teal js-expand-trigger"><span class="icon icon-plus--teal expandable__cta-icon"></span>All Doctors</h4>
<div class="expandable__content js-favorite-doctor-row-container" aria-expanded="true">
<div class="location-section dr-profile">
<div class="section__content js-doctor-row">
<div class="favorite-doctor-manage__row">
DR info
</div>
</div><!--/section__content-->
</div><!--/location-section-->
</div><!--/expandable__content-->
Tag section to remove groups
<div class="js-favorite-doctor-manage-add-remove">
<div class="grid-construct">
<div class="expandable" data-controller="expandable">
<ul class="tag-list js-group-list" tabindex="-1">
<li class="tag tag--teal" >
Lauren's Doctors
<ul class="tag-sub">
<li><button class="tag-icon tag-icon--close-white js-group-remove">Remove group: Lauren's Doctors</button></li>
</ul>
</li>
<li class="tag tag--teal" >
Timmy's Doctors
<ul class="tag-sub">
<li><button class="tag-icon tag-icon--close-white js-group-remove">Remove group: Timmy's Doctors</button></li>
</ul>
</li>
</ul>
</div>
removeGroup: function( evt ) {
var deleteGroup = function() {
if ( $(evt.currentTarget).closest('.tag').hasClass('is-active')){
var clickedTag = $(evt.currentTarget).closest('.tag');
var groupList = this.$el.find('.js-group-list');
var groupTags = groupList.find('.tag');
var index = groupTags.index(clickedTag);
var groupSections = $('.js-favorite-group');
// add one to account for "All" section which is never removed
var groupToRemove = groupSections.eq(index + 1);
console.log(groupToRemove);
var removedGroupName = this.getGroupNameForSection(groupToRemove);
var allDoctors = groupSections.eq(0);
var allDoctorsContainer = allDoctors.find('.js-favorite-doctor-row-container');
if ( index > -1 ){
groupToRemove.find('.js-favorite-doctor-row').appendTo(allDoctorsContainer);
clickedTag.remove();
groupToRemove.remove();
this.updateSectionDropdowns();
this.ariaAlert('Group ' + removedGroupName + ' removed');
this.hideConfirm(evt);
}
}
};
this.showAlert(evt, deleteGroup);
},
showAlert: function (evt, callback) {
that = this;
var clickedTag = '';
clickedTag = $(evt.currentTarget).closest('.tag');
clickedTag.addClass('is-active').attr('data-delete','true');
$('.delete-acct-message').show().focus();
$('.js-remove-yes').on('click', function(evt){
evt.preventDefault();
callback.apply(that);
});
$('.js-remove-no').on('click', function(evt){
evt.preventDefault();
this.hideConfirm(evt);
});
},
I would suggest that you should use custom attributes in your html, this will simplify your javascript logic and make it more effective and efficient.
I have modified your html and javascript to add the support for custom attribute data-doc-group. Have a look at your group sections div here
<div data-doc-group="lauren" class="section-border-top--grey js-favorite-group">
<h4 class="expandable__cta cta--std-teal js-expand-trigger"><span class="icon icon-plus--teal expandable__cta-icon"></span>Lauren's Doctors</h4>
<div class="expandable__content js-favorite-doctor-row-container" aria-expanded="true">
<div class="location-section dr-profile">
<div class="section__content js-doctor-row">
<div class="favorite-doctor-manage__row">
DR info
</div>
</div><!--/section__content-->
</div><!--/location-section-->
</div>
Here are the tags with custom attributes
<li data-doc-group="lauren" class="tag tag--teal">
Lauren's Doctors
<ul class="tag-sub">
<li><button class="tag-icon tag-icon--close-white js-group-remove">Remove group: Lauren's Doctors</button></li>
</ul>
</li>
<li data-doc-group="timmy" class="tag tag--teal">
Timmy's Doctors
<ul class="tag-sub">
<li><button class="tag-icon tag-icon--close-white js-group-remove">Remove group: Timmy's Doctors</button></li>
</ul>
</li>
Here is the javascript to handle this, (this may be a bit buggy, but will give you a general idea)
removeGroup: function(evt) {
this.showAlert(evt, function() {
var $clickedTag = $(evt.currentTarget).closest('.tag'),
dataGroupName,
$groupToRemove,
removedGroupName,
$allDoctors = $('.js-favorite-group').eq(0),
$allDoctorsContainer = $allDoctors.find('.js-favorite-doctor-row-container');
if ($clickedTag.hasClass('is-active')){
dataGroupName = $clickedTag.data('doc-group');
$groupToRemove = $allDoctors.siblings('[data-doc-group="' + docGroupName + '"]');
if ($groupToRemove.length > 0){
$groupToRemove.find('.js-favorite-doctor-row').appendTo($allDoctorsContainer);
$clickedTag.remove();
$groupToRemove.remove();
removedGroupName = this.getGroupNameForSection($groupToRemove);
this.updateSectionDropdowns();
this.ariaAlert('Group ' + removedGroupName + ' removed');
this.hideConfirm(evt);
}
}
});
}

Ask for multiple id's with the same data attribute

I'm trying to check for a data attribute in multiple list items.
My HTML:
<ul id="year">
<li id="2006">2006</li>
<li id="2007">2007</li>
<li id="2008">2008</li>
<li id="2009">2009</li>
<li id="2010">2010</li>
<li id="2011">2011</li>
<li id="2012">2012</li>
<li id="2013">2013</li>
<li id="2014">2014</li>
</ul>
And this is the jQuery:
jQuery('#year li').click(function()
{
var year = jQuery(this).attr('id');
if ((jQuery(this).data('state') === undefined) || (jQuery(this).data('state') == "off"))
{
jQuery(this).data('state', 'on');
}
else
{
jQuery(this).data('state', 'off');
}
});
Now i am trying to check if there are any list items where the "state" == "on"
Like this:
if ((jQuery('#year li').data('state') == "on"))
But it does not seem to be working...
EDIT: So i tried all the different snippets you gave me: none of them worked so i made a simple for loop that looks in every list point itself:
for ( var y = 2006, l = 2015; y < l; y++ )
{
if ((jQuery('#year #'+y).data('state') == "on"))
{
alert('data found');
}
Another problem was that i didnt had any event before my code!
Thanks for the support!
the jQuery('#year li') will return an array of jquery objects.
you will need to loop each one
$('#year li').each(function () {
if ((jQuery(this).data('state') === "on")){
alert("on state found");
}
});
You can use .filter() then check length property
var list = jQuery('#year li').filter(function(){
return $(this).data('state') == "on";
//OR, using native dataset
//return this.dataset.state == 'on'
});
if (list.length){
//li with state on exits
}
The reason this doesn't work for you is that jQuery doesn't store data values in the "standard" element dataset. You can acheive your goal by doing that yourself:
$('#year li').click(function() {
this.dataset.state = this.dataset.state === 'off' ? 'on' : 'off';
if($('#year li[data-state="on"]').length > 0) {
alert('Found!')
}
});
#year li[data-state="on"] {
color: blue;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<ul id="year">
<li id="2006">2006</li>
<li id="2007">2007</li>
<li id="2008">2008</li>
<li id="2009">2009</li>
<li id="2010">2010</li>
<li id="2011">2011</li>
<li id="2012">2012</li>
<li id="2013">2013</li>
<li id="2014">2014</li>
</ul>

Onclick function changing to the same function for all changed elements

What I'm trying to do is based on data gotten via AJAX I am changing certain elements on the page to be different. A simplified version is this:
Example:
HTML:
<ul id="friends">
<li id="1-1" onclick="dont_alert()"> Andy </li>
<li id="1-2" onclick="dont_alert()"> Paul </li>
<li id="1-3" onclick="dont_alert()"> Saul </li>
<li id="1-4" onclick="dont_alert()"> Rita </li>
<li id="1-5" onclick="dont_alert()"> Greg </li>
</ul>
<input type="button" onclick='callback()' value="Go!" />
Relevant JS:
function alert_this(value) {
alert(value);
}
function dont_alert() {
alert('...');
}
function callback() {
var data_received = [["1","1","Andy"], ["1","5","Greg"]];
for (friend in data_received) {
if (data_received[friend][0] == undefined) continue;
var friend_id = '#'+ data_received[friend][0] +'-'+ data_received[friend][1];
$(friend_id).attr('onclick', '');
$(friend_id).css('background', 'red');
$(friend_id).click(function () {
alert_this(data_received[friend][2]);
});
}
}
The result of this is both elements alert 'Greg' instead of the appropriate value.
Any prod towards the answer will be very much appreciated! :D
You need to create a closure, otherwise, the .click() handler will always alert the value of the last assigned friend in the loop, since all they have is a reference to this variable.
function callback() {
var data_received = [["1","1","Andy"], ["1","5","Greg"]];
for (var friend in data_received) {
if (data_received[friend][0] == undefined) continue;
var friend_id = '#'+ data_received[friend][0] +'-'+ data_received[friend][1];
console.log(friend_id);
$(friend_id).attr('onclick', '');
$(friend_id).css('background', 'red');
(function() {
var savedValue = data_received[friend][2];
$(friend_id).click(function(){
alert(savedValue);
});
})();
}
}​
DEMO.
First off, you shouldn't be using inline event handlers in your HTML. Instead, attach them with jQuery.
Your problem is with closures - friend has function scope, within callback. The event handlers create a closure on the friend variable. When callback finished, friend == 1. The event handlers then use this value. A fix is to use $.each to iterate your arrays, which creates a closure on the value of the variable.
HTML
<ul id="friends">
<li id="1-1"> Andy </li>
<li id="1-2"> Paul </li>
<li id="1-3"> Saul </li>
<li id="1-4"> Rita </li>
<li id="1-5"> Greg </li>
</ul>
<input type="button" id="go" value="Go!" />
Js
$('#friends').on('click', 'li', function() {
alert('...');
});
$('#go').on('click', function() {
var data_received = [["1","1","Andy"], ["1","5","Greg"]];
$.each(data_received, function(i, friend) {
if (friend[0] === undefined) return;
$('#'+ friend[0] +'-'+ friend[1])
.css('background', 'red');
.click(function() {
alert(friend[2]);
return false;
});
});
});

Categories

Resources