Lightning – How to Get Hover for Specific Row When Values Are Iterated

I have iterated list and over a column i need was implementing the hover functionality. I get the hover popup but i get it for all rows and its flickering.example if i have 5 rows and i hover on 2nd i get the hover layout for all 5 rows.

                            <aura:iteration items="{!v.SelectedWrapperItems}" var="vSWI" indexVar="index">

                            <tr class="" id="trow" data-selected-Index="{!index}">
                                <td class="slds-cell-wrap" style="width:5%">
                                    <ui:outputText value="{!vSWI.wRow + 1}" />
                                </td>
                                <td class="slds-cell-wrap slds-size--2-of-12">


                                    <ui:outputText value="{!vSWI.owOLI.Product_Service__r.Name}" />
                                </td>

                                <td class="slds-cell-wrap slds-size--1-of-12">

                                    <a href="{!'/one/one.app?#/sObject/' +vSWI.owOLI.OpportunityProductBundle__c + '/view'}"
                                       data-recId="{!vSWI.owOLI.OpportunityProductBundle__c}" data-index="{!index}"
                                       target="_blank" onmouseover="{!c.handleMouseOver}" onmouseout="{!c.handleMouseOut}" 
                                       tabindex="-1">
                                        {!vSWI.owOLI.OpportunityProductBundle__r.Name}
                                        <aura:if  isTrue="{!v.togglehover}">


                                            <div style="padding-left: 2rem; padding-top: 5rem; position: relative;">

                                                <div   class="slds-popover slds-popover_tooltip slds-nubbin_bottom-left slds-rise-from-ground" 
                                                     role="tooltip" id="help" style="position: absolute; top: 0px; left: 15px;">
                                                    <div class="slds-popover__body"> 
                                                        Id: {!v.hoveropb.Id}
                                                        Name: {!v.hoveropb.Name} </div>
                                                </div>
                                            </div>    
                                        </aura:if>      
                                    </a> 
                          </td>  </aura:iteration>

and my JS is

 handleMouseOver : function(component,event,helper){

    var id1=event.currentTarget.getAttribute("data-recId");

    var action=component.get("c.getopportunityBundleProducts");
    action.setParams({
        "bid":id1 
    });
    action.setCallback(this,function(re) { 
        var state=re.getState(); 
        if(state==='SUCCESS'){
             component.set("v.togglehover",true);
             component.set("v.hoveropb",re.getReturnValue());
        } 
    }); 
    $A.enqueueAction(action); 
},
handleMouseOut : function(component,event,helper){

    component.set("v.togglehover",false);

}

this is what the output looks like.

Best Answer

In order to show the hover on just one row, you need a way to identify the row. Personally, I would have used CSS if practical, but since you're already down this path, here's how you'd use aura:if correctly.


Add an attribute to know which row should display the hover.

<aura:attribute name="hoverRow" type="Integer" default="-1" />

...

Change aura:if to check if the index matches the hoverRow:

<aura:if isTrue="{!v.hoverRow==index}">

...

Set the data row from the index value you already have available.

if(state==="SUCCESS") {
  component.set("v.hoverRow", parseInt(event.target.dataset.index));

...

And finally, to hide the hover, reset back to -1.

handleMouseOut:function(component,event,helper){
    component.set("v.hoverRow",-1);
}

Edit:

As CSS, you'd instead want to just toggle the visibility for the element. First, remove the aura:if, and add the slds-hide class and an aura:id:

    <div aura:id="hover" class="slds-hide" style="padding-left: 2rem; padding-top: 5rem; position: relative;">

Then, you can update your functions:

if(state==="SUCCESS") {
  var items = component.find("hover");
  if(!items.length) items = [items];
  $A.removeClass(items[parseInt(event.target.dataset.index)],'slds-hide');

And:

handleMouseOut:function(component,event,helper){
  var items = component.find("hover");
  if(!items.length) items = [items];
  $A.addClass(items[parseInt(event.target.dataset.index)],'slds-hide');
}

You can shorten this code a bit if you use a helper class for reusable functions.