[SalesForce] How to set focus on a lightning:input, generated inside a aura:iteration, from controller method triggered by another element’s event

I have an Aura component with an aura:iteration that each iteration generates a lightning:formattedNumber, a hidden lightning:input (both for the same field), and a lightning:buttonIcon that calls a controller method that hides the first and shows the second one.

I want to show and focus the lightning:input after I click the button, but I'm not able to use the .focus() method, because I can't get the component with .find(), since It seems I can't dynamically set aura:id.

Also, I tried to use a parent span with an id to access the input tag generated by the lightning:input with something like document.querySelector('#myDynamicIdValue input'), but it returns only null.

How could I focus this input?

enter image description here


Update: The solution I ended up, based on the answers and some specific needs, was to set a generic value in the aura:Id and unique value in the name of the lightning:input (mixing the name field + item Id, that's because I also have multiple inputs in each iteration, and each block generated by the loop can be sorted, so in this case numeric indexes might not be the best fit), and set the same unique value in some attribute where the event starts, then in the event handler I can filter the input list by this unique value:

markup:

<aura:iteration items="{!v.items}" var="item">
    <label class="slds-form-element__label slds-p-around_none">Quantity</label>
    <span class="slds-grid slds-grid_align-spread ps-itemInlineOutput" id="{! 'itemQuantity' + item.Id}" ondblclick="{!c.onShowInlineEdit}">
        <lightning:formattedNumber value="{!item.Quantity}" />
        <lightning:buttonIcon iconName="utility:edit" variant="bare" class="slds-m-left_x-small" name="{! 'itemQuantity' + item.Id}" onclick="{!c.onShowInlineEdit}" />
    </span>
    <span class="slds-grid slds-grid_align-spread ps-itemInlineInput slds-hide" id="{! 'itemQuantity' + item.Id}" onkeyup="{!c.onHideInlineEdit}">
        <lightning:input type="number" variant="label-hidden" value="{!item.Quantity}" aura:id="itemInput" name="{! 'itemQuantity' + item.Id}" onblur="{!c.onHideInlineEdit}" />
    </span>
</aura:iteration>

controller:

onShowInlineEdit: function (component, event, helper) {
    var itemId = event.currentTarget.id != null ? event.currentTarget.id : event.getSource().get('v.name');
    document.querySelector("#" + itemId + ".ps-itemInlineOutput").classList.add('slds-hide');
    document.querySelector("#" + itemId + ".ps-itemInlineInput").classList.remove('slds-hide');
    component.find('itemInput').find(itemInput => itemInput.get('v.name')==itemId).focus();
},

result:

enter image description here

Thanks!

Best Answer

You can attach an iteration value to each row, then use that to figure out which input to focus.

<aura:iteration items="{!v.items}" var="item" indexVar="index">
  <div class="..." data-index="{!index}">
    ...
    <lightning:input aura:id="itemInput" ... />

Then, for your click handler:

onShowInlineEdit: function(component, event, helper) {
  let index = parseInt(event.target.closest("[data-index]").dataset.index);
  let inputs = component.find("itemInput");
  inputs[index].focus();
}

This is essentially a version of my own problem that I had.