0

I have a lightning component that displays a modal when a button is clicked. Based on the ID stored in the dataset of the clicked element when the modal is loaded the action should look for a div that contains the ID and set it to display block. But I'm running into an issue where when I look for the div it should unhide it returns null.

component:

<aura:component controller="DataDictionaryController" implements="flexipage:availableForAllPageTypes" access="global" >
    
    <aura:attribute name="dataFields" type="Data_Field__c[]" />
    <aura:attribute name="dataObjectId" type="String" />
    <aura:attribute name="isModalOpen" type="boolean" default="false"/>
    
    <aura:handler name="init" value="{!this}" action="{!c.doInit}" />
    <div class="card-body">
        <div class="table-responsive">
            <table class="table table-bordered" id="dataTable" width="100%" cellspacing="0">
                <thead>
                    <tr>
                        <th></th>
                        <th>Label</th>
                        <th>API Name</th>
                        <th>Data Type</th>
                        <th>Owner</th>
                        <th>Description</th>
                    </tr>
                </thead>
                <tfoot>
                    <tr>
                        <th></th>
                        <th>Label</th>
                        <th>API Name</th>
                        <th>Data Type</th>
                        <th>Owner</th>
                        <th>Description</th>
                    </tr>
                </tfoot>
                <tbody>
                    
                <aura:iteration items="{!v.dataFields}" var="item">
                    <tr>
                        <td>
                            <div onclick="{!c.openModal}" data-id="{!item.Id}" class="hello">
                                <lightning:button variant="brand" label="Info" title="Info" />
                            </div>
                        </td>
                        <td>{!item.Label__c}</td>
                        <td>{!item.Name}</td>
                        <td>{!item.Data_Type__c}</td>
                        <td>{!item.Business_Owner_ID__c}</td>
                        <td>{!item.Description__c}</td>
                    </tr>    
                </aura:iteration>
                    
                </tbody>
            </table>
        </div>
    </div>
    
    <div class="slds-m-around_xx-large">
        <aura:if isTrue="{!v.isModalOpen}">
            <section id="dataFieldModal" role="dialog" tabindex="-1" aria-labelledby="modal-heading-01" aria-modal="true" aria-describedby="modal-content-id-1" class="slds-modal slds-fade-in-open">
                <div class="slds-modal__container">
                    <header class="slds-modal__header">
                        <h2 id="modal-heading-01" class="slds-text-heading_medium slds-hyphenate">Field Details</h2>
                    </header>
                    <!--Modal/Popup Box Body Starts here-->
                    <div class="slds-modal__content slds-p-around_medium" id="modal-content-id-1">
                        <aura:iteration items="{!v.dataFields}" var="item">
                            <div aura:id="modal" data-id="{!item.Id}" style="display: none" >
                                <p>
                                    Info goes here...<br />
                                    {!item.Id}<br />
                                    {!item.Name}
                                </p>
                            </div>
                        </aura:iteration>
                    </div>
                    <footer class="slds-modal__footer">
                        <lightning:button variant="neutral" label="Close" title="Close" onclick="{! c.closeModel }"/>
                    </footer>
                </div>
            </section>
            <div class="slds-backdrop slds-backdrop_open"></div>
        </aura:if>
    </div>    
    
</aura:component>

controller

({
    doInit : function(component, event, helper) {
        var pathname = window.location.pathname;
        var pathArray = pathname.split("/");
        var sfObject = "";
        var isLightningApp = true;
        if (pathArray[1] == 'lightning') {
            sfObject = pathArray[3];
            isLightningApp = false;
        }
        
        if (isLightningApp) {
            var dataObjectId = component.get("v.dataObjectId");
            var action = component.get("c.getDataFields");       
            action.setParams({ recordId : dataObjectId });
            action.setCallback(this, function(data){
                component.set("v.dataFields",data.getReturnValue());
            });
        } else {
            var action = component.get("c.getDataFieldsByObjectName");
            action.setParams({ name : sfObject });
            action.setCallback(this, function(data) {
                component.set("v.dataFields",data.getReturnValue());
            });
        }
        $A.enqueueAction(action);

    },
    
    
    openModal: function(component, event, helper) {
      let modals = component.find("modal");
      let desiredModal = modals.find(
        (modal) => modal.getElement().dataset.id === event.target.dataset.id
      );
      console.log(desiredModal);
      desiredModal.getElement().style.display = 'block';
    },
    
   closeModel: function(component, event, helper) {
       // Set isModalOpen attribute to false
       console.log('closeModal');
       component.set("v.isModalOpen", false);
   },


})

The error I get is: "Uncaught Action failed: c:DataObjectDetail$controller$openModal [Cannot read properties of undefined (reading 'find')]."

Any help would be much appreciated!!

2 Answers 2

1

You've got a few problems. First, you can't reliably get an element's Id like this; they get modified by the runtime. Second, components end up wrapped up in a SecureComponent, so you have to access them differently. The code you actually need ends up looking like this:

<div onclick="{!c.openModel}" data-id="{!item.Id}" class="hello">

...

<div aura:id="modal" data-id="{!item.Id}" style="display: none" >

...

openModal: function(component, event, helper) {
  let modals = component.find("modal");
  let desiredModal = modals.find(
    (modal) => modal.getElement().dataset.id === event.target.dataset.id
  );
  desiredModal.getElement().style.display = 'block';
}

Note that aura:id is not evaluated, so we need to find the element "manually".

Note: as an extra twist, if component.find finds zero or one elements, you'll get undefined or a SecureComponent, respectively, rather than an Array. You'll need to check for these conditions.

5
  • Thanks for this! I'm still getting an error when I implement what you have here I get the following: Uncaught Action failed: c:DataObjectDetail$controller$openModal [Cannot read properties of undefined (reading 'find')]. I think the problem is basically what you were saying but I'm not sure how to get around this.
    – dkeefer
    Commented Nov 18, 2022 at 15:43
  • @dkeefer Did you add the aura:id? Do you have more than one element in your list of modals? component.find returns either undefined, a SecureComponent, or an Array of SecureComponent elements, depending on if there are zero, one, or more than one elements, respectively.
    – sfdcfox
    Commented Nov 18, 2022 at 16:46
  • Yep, I added the aura:id. Is the issue that it creates multiple <div aura:id="modal" data-id="{!item.Id} style="display: none"> elements? It looks like the find method isn't getting far enough to return a result.
    – dkeefer
    Commented Nov 18, 2022 at 18:21
  • @dkeefer That's not an issue, that's how it's supposed to be. You need to find the correct element, as demonstrated in this code. I actually wrote this in my org, so I know it works. Can you update your question's code?
    – sfdcfox
    Commented Nov 18, 2022 at 18:28
  • I updated the code above for both the component and the controller. I also included the entire controller just in case it was something else that was causing a problem. I really appreciate all the help!
    – dkeefer
    Commented Nov 18, 2022 at 18:56
1

Salesforce doesn't guarantee the global id:

Every component has a unique globalId, which is the generated runtime-unique ID of the component instance. A global ID (1) is not guaranteed to be the same beyond the lifetime of a component, so it should never be relied on.

https://developer.salesforce.com/docs/atlas.en-us.lightning.meta/lightning/components_ids.htm

What Salesforce suggest is to use local Ids:

    <section aura:id="dataFieldModal" role="dialog" tabindex="-1" aria-labelledby="modal-heading-01" aria-modal="true" aria-describedby="modal-content-id-1" class="slds-modal slds-fade-in-open">
     openModel: function(component, event, helper) {
        component.set("v.isModalOpen", true);
        var ctarget = event.target;
        var modalobj = component.find("dataFieldModal").getElement());
        modalobj.style.display = "block";
    },

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .