[SalesForce] Lightning component – aura:iteration, add class to selected item

I display a menu in a lightning component.
For that I get dynamically the element of the menu, and I display them with an aura:iteration, like this :

<ul class="messages-list" aura:id="main">
   <aura:iteration items="{!v.lThemes}" var="theme">
      <li class="message-item" onclick="{!c.getSelectedTheme}" data-id="{!theme.DeveloperName}" aura:id="{!theme.DeveloperName}">
            <a href="#" >
              <i class="{!'icon ' + theme.Icone__c}"></i>
              <span class="subject">{!theme.Theme__c}</span>
            </a>
       </li>
   </aura:iteration>
</ul>

In the <li> tag, I need to insert a class 'current' so I can apply some style to the selected element, when clicked.
I try to do it with the JS method :

getSelectedTheme : function(component, event, helper){

    var selectedItem = event.currentTarget;
    var id = selectedItem.dataset.id;
    console.log('id : ' + id);

    var alreadySelectedElement = document.getElementsByClassName("current");
    for (var i = 0; i < alreadySelectedElement.length; i ++) {
        var val = alreadySelectedElement[i].getAttribute('data-id');
        alreadySelectedElement = component.find(val);
        console.log('val : ' + val);
        if(val != id){
            $A.util.removeClass(alreadySelectedElement, "current");
        }
    }

    var selectedElement = component.find(id);
    $A.util.addClass(selectedElement, "current");

}

But it does not work. If I use it with a non dynamic list (without aura:iteration) it works… But I need to make this list dynamic.

EDIT——-

I tried to change the component like this :

<aura:iteration items="{!v.lThemes}" var="theme" indexVar="indx">
    <li class="message-item" onclick="{!c.getSelectedTheme}" data-id="{!indx}" aura:id="testli" data-theme="{!theme.Theme__c}">
        <a href="#" >
            <i class="{!'icon ' + theme.Icone__c}"></i>
            <span class="subject">{!theme.Theme__c}</span>
        </a>
    </li>
</aura:iteration>

with the method of the controller :

var selectedItem = event.currentTarget;
    var id = selectedItem.dataset.id;

    var Elements = component.find('testli');
    console.log('Elements.length : ' + Elements.length);
    for (var i = 0; i < Elements.length; i++) {
        var val = Elements[i].getElement().getAttribute('data-id');

        if(val != id &&  $A.util.hasClass(Elements[i], "current")){
            $A.util.removeClass(Elements[i], "current");
        } else {
            $A.util.addClass(Elements[i], "current");
        }
    }

But it doesn't work as expected, the first time I click on an element, all the elements are selected (the class is applied to all) and after that if I click another element, it i correctly selected, but then if I click another element, the previous is deselected, but all the others are selected…

Best Answer

  1. Firstly You can't dynamically set aura:id based on aura:attribute for any component.Workaround( you can dynamically create the component using $A.createComponent and you can set aura:id dynamically).

  2. For this scenerio you can also create a child component for 'li' tag to change a class based on the element you click . By this you can avoid aura:id issue.

  3. You can also create using a single component itself by getting aura:Id as list and do the stuff there you have done some mistake in your code. I have included a sample code

    EXAMPLE:

Component:

<aura:component>
    <ul class="messages-list" aura:id="main">
        <aura:iteration items="['1','2']" var="theme" indexVar="indx">
            <li aura:id="testli" class="message-item" onclick="{!c.getSelectedTheme}" data-id="{!indx}" >
                {!indx}
            </li>
        </aura:iteration>
    </ul>
</aura:component >

Controller:

({
    getSelectedTheme : function(component, event, helper){

        var selectedItem = event.currentTarget;
        var id = selectedItem.dataset.id;

        var Elements = component.find('testli');

        for (var i = 0; i < Elements.length; i++) {
            var val = Elements[i].getElement().getAttribute('data-id');

            if(val != id){
                $A.util.removeClass(Elements[i], "current");
            } else {
                $A.util.addClass(Elements[i], "current");
            }
        }


    }
})