Unable to get property 'apiName' of undefined or null reference - Answers - Salesforce Trailblazer Community
Trailblazer Community
Ask Search:
Liubomyr MalanchakLiubomyr Malanchak 

Unable to get property 'apiName' of undefined or null reference

Hi All, I'm currently struggling with a strange error message in my Aura component, any kind of pointers or further debugging ideas would be most welcome! Thanks in advance!
So the setup is:
  • A custom object (Risk__c) has a lookup relationship to Parent (Account).
  • The number of risks related to the parent depend on the rating of the Account (basically if rating = 'Hot', then number of risks is reduced by 1).
  • There's a before update Account trigger that takes care of the latter.
  • The aura component is just a list of risks attached to the account, grouped by year.
  • the RiskManagement apex controller provides data in the following format (wrapped object): List<WrapRiskYear>
  • WrapRiskYear is also a wrapped object and contains a Map<Integer,List<WrapRisk>>
  • WrapRisk is another (last) wrapped object that contains: the Risk__c object + a boolean flag if it's updateable or not. 
  • Aura component consists of 3 sub-components:
    • Risk Tab (embedded on the record page, serves as the parent)
      •  Risk List (iterates over each year in List<WrapRiskYear>)
        • Risk Item (iterates over each risk object in that year
  • Once the Account record changes, an LDS force:recordData component listens for recordUpdated events and re-initializes the parent component, to refresh the list of risks.
Ok done with the setup.
Now when I update the account rating to 'Hot', the trigger deletes the link between account and Risk__c for one of the risks, and the list of risks (parent component) on the Account record page should refresh.
While I did get the component to refresh, unfortunately I'm also seeing a bunch of errors thrown by the browser (in the subject).
The same happens if I reverse the order and set the rating back to 'Hot', the trigger re-adds the risk back to account and the errors happen on component re-initialization. One particular thing I noticed is that the error seems to correlate with the new amount of risks. (occurs 3 times on Account rating update to Hot, and 4 times on Account update to Cold)

User-added image
User-added image
User-added image
User-added image
User-added image
What exactly is the meaning behind this error?
It feels like the child components try to iterate ove an object that doesn't exist anymore and start complaining about the null reference. But I'm at a loss on how to troubleshoot this further to narrow down the scope to the actual problem.

Also feel free to recommend a different, better approach how to refresh a component on the record page once the record itself changes.

Here's the code:
Server Side Controller:
public with sharing class RiskMgmtController {
    @AuraEnabled
    public static List<WrapRiskYear> getRiskData(Id recordId, String sObjectName){
        Map<Integer,List<WrapRisk>> wrapRisksObjs = new Map<Integer,List<WrapRisk>>();
        switch on sObjectName {
            when 'Account' {
                List<Risk__c> risks = getAccRisks(recordID);
                for(Risk__c r : risks){
                    Integer year = (r.YearCompleted__c != NULL) ? r.YearCompleted__c.intValue() : Date.today().year();
                    if(!wrapRisksObjs.containsKey(year)){
                        wrapRisksObjs.put(year, new List<WrapRisk>());
                    }
                    WrapRisk riskObj = new WrapRisk();
                    riskObj.risk = r;
                    riskObj.isUpdateable = (Schema.sObjectType.Risk__c.isUpdateable() && r.YearCompleted__c!= NULL);
                    wrapRisksObjs.get(year).add(riskObj);
                }
            }
            when else {
                //nothing yet
            }
        }
        List<WrapRiskYear> wrapRisksObjsList = new List<WrapRiskYear>();
        for(Integer year : wrapRisksObjs.keySet()){
            WrapRiskYear riskListObj = new WrapRiskYear();
            riskListObj.year = year;
            riskListObj.risks = wrapRisksObjs.get(year);
            wrapRisksObjsList.add(riskListObj);
        }
        return wrapRisksObjsList;
    }
    //wrapper classes
    public class WrapRisk{
        @AuraEnabled
        public Risk__c risk{get; set;}
        @AuraEnabled
        public Boolean isUpdateable{get; set;}   
    }
    public class WrapRiskYear{                
        @AuraEnabled
        public Integer year{get; set;}  
        
        @AuraEnabled
        public List<WrapRisk> risks{get; set;}
    }
    
    private static List<Risk__c> getAccRisks (Id recordId) {
        return [SELECT Id, Name, YearCompleted__c FROM Risk__c WHERE Account__c =:recordId order by YearCompleted__c DESC];
    }
}
Account Trigger
trigger AccountTrigger on Account (before update) {
    for(Account acc: Trigger.New){
        if(acc.Rating == 'Hot'){
            Risk__c riskToUpdate = [SELECT Id, Name, Parent__c, Account__c FROM Risk__c WHERE Parent__c =:acc.Id AND Name = 'A' LIMIT 1];
            riskToUpdate.Account__c = NULL;
            update riskToUpdate;
        }else{
            Risk__c riskToUpdate = [SELECT Id, Name, Parent__c, Account__c FROM Risk__c WHERE Parent__c =:acc.Id AND Account__c = NULL LIMIT 1];
            riskToUpdate.Account__c = acc.Id;
            update riskToUpdate;
        }
    }
}
Risk Management Tab component (Parent component)
<aura:component controller="RiskMgmtController" implements="flexipage:availableForRecordHome,force:hasRecordId,force:hasSObjectName" access="global" >
    <aura:attribute name="risksData" type="Object[]"/>

    <force:recordData aura:id="accountService"
    recordId="{!v.recordId}"
    recordUpdated="{!c.doInit}"
    fields="Name"/>
    
    <lightning:card iconName="custom:custom60" title="Risks Identified" class="slds-is-relative">
        <div class="slds-list_vertical slds-has-dividers_top-space">
            <ul>
                <lightning:accordion aura:id="accordion">
                    <aura:iteration items="{!v.risksData}" var="yearData">
                        <lightning:accordionSection name="{!yearData.year}" label="{!yearData.year}">
                            <c:RiskItemLst yearData="{!yearData}"/>
                        </lightning:accordionSection>
                    </aura:iteration>
                </lightning:accordion>
            </ul>
        </div>
    </lightning:card>
    <lightning:spinner aura:id="spinner" variant="brand" size="medium" alternativeText="Loading Risks"/>
</aura:component>
Risk Management Tab component controller:
({
    doInit : function(component, event, helper) {
        var changeType = event.getParams().changeType;
        if (changeType === "ERROR") {}
        else if (changeType === "LOADED") {
            helper.h_doInit(component, event);
        }
            else if (changeType === "REMOVED") {}
                else if (changeType === "CHANGED") {
                    helper.h_doInit(component, event);
                }
    }
})
It's helper:
({
    h_doInit : function(component, event) {
        var spinner = component.find("spinner");
        $A.util.removeClass(spinner, "slds-hide");
        var action = component.get("c.getRiskData");
        action.setParams({
            recordId: component.get("v.recordId"),
            sObjectName: component.get("v.sObjectName")
        });
        
        action.setCallback(this, function(response){
            var state = response.getState();
            var result = response.getReturnValue();
            component.set("v.risksData", result);
            $A.util.addClass(spinner, "slds-hide");
        });
        $A.enqueueAction(action);
    }
})
First Nested Risk List component (Risk Data by Year)
<aura:component >
    <aura:attribute name="yearData" type="Object"/>
    
    <ul class="slds-list_vertical slds-has-dividers_top-space">
        <aura:iteration items="{!v.yearData.risks}" var="item">
            <li class="{!item.isUpdateable ? 'slds-list__item' : 'slds-list__item slds-theme--shade'}">
                <c:RiskItem riskItem="{!item.risk}" isUpdateable="{!item.isUpdateable}"/>
            </li>
        </aura:iteration>
    </ul>
    
</aura:component>
The second nested Risk Item component (Actual risks - Risk__c)
<aura:component>
    <aura:attribute name="riskItem" type="Risk__c"   />
    <aura:attribute name="isUpdateable" type="Boolean" default="false"/>    
    <lightning:recordViewForm aura:id="viewForm"  recordId="{!v.riskItem.Id}" objectApiName="Risk__c" density="Comfy">
        <lightning:outputField fieldName="Name"/>
    </lightning:recordViewForm>
</aura:component>


 
Liubomyr MalanchakLiubomyr Malanchak
Ran out of screen space, just adding that the error message only shows up in the dev console of IE or edge, Chrome seems to be showing a slightly different wording of the error (screen above).
User-added image