2

Okay this is a weird one. I have an aura component that I put on our user record pages that display that user's open opportunities. I pull the recordId from the URL, run SOQL to grab all open opps for that recordId, then go from there. All that works perfectly.

The hitch is I wanted the list to be titled "User's Open Opportunities" unless you were looking at your own profile, then it says "MY Open Opportunities." Wrote a function to set the title card that compares the active user's ID to the record user's ID, then sets the title card accordingly. And it works....about half the time. But then sometimes it's "null's Open Opportunities." To be clear, the recodId must be loading properly because the list itself always has the right user's opportunities, it's just the name not loading properly. Here's my component, controller and helper

MyOpenOpportunities.cmp

<aura:component controller="MyOpenOpportunitiesController" implements="flexipage:availableForAllPageTypes,force:hasrecordId" access="global" >
    <aura:handler name="init" value="{!this}" action="{!c.doInit}" />
    <aura:attribute name="recordId" type="Id" />
    <aura:attribute name="Opportunities" type="Opportunity[]" />
    <aura:attribute name="Columns" type="List" default="[
        {'label': 'Opportunity Name', 'fieldName': 'Name', 'type': 'text'},
        {'label': 'Stage', 'fieldName': 'StageName', 'type': 'text'},
        {'label': 'Account Name', 'fieldName': 'Account.Name', 'type': 'text'}
    ]" />
    <aura:attribute name="cardTitle" type="String"/>
    <aura:attribute name="user" type="User" />

    <lightning:card iconName="user" title="{!v.cardTitle}">
        <lightning:datatable data="{! v.Opportunities }" columns="{! v.Columns }" keyField="Id" hideCheckboxColumn="true"/>
    </lightning:card>
</aura:component>

MyOpenOpportunitiesController.js

 ({
        doInit : function(component, event, helper) {
            helper.fetchUser(component);
            helper.fetchOpportunities(component);
            helper.setCardTitle(component);
        }
    })

MyOpenOpportunitiesHelper

({
    fetchUser : function(component) {
        var action = component.get("c.getUser");
        action.setParams({
            userId: component.get("v.recordId")
        });

        action.setCallback(this, function(response) {
            var state = response.getState();
            if (state === "SUCCESS") {
                component.set("v.user", response.getReturnValue());
            } else if (state === "ERROR") {
                var errors = response.getError();
                console.error(errors);
            }
        });

        $A.enqueueAction(action);
    },

    fetchOpportunities : function(component) {
        var action = component.get("c.getOpenOpportunities");
        action.setParams({
            recordId: component.get("v.recordId")
        });

        action.setCallback(this, function(response) {
            var state = response.getState();
            if (state === "SUCCESS") {
                component.set("v.Opportunities", response.getReturnValue());
            } else if (state === "ERROR") {
                var errors = response.getError();
                console.error(errors);
            }
        });

        $A.enqueueAction(action);
    },
    setCardTitle : function(component) {
        var action = component.get("c.getCurrentUserId");
        action.setCallback(this, function(response) {
            var state = response.getState();
            if (state === "SUCCESS") {
                var currentUserId = response.getReturnValue();
                var recordId = component.get("v.recordId");
                var recordUserName = component.get("v.user.Name");
                var condition = (currentUserId === recordId);
                var title = condition ? "My Open Opportunities" : recordUserName + "'s Open Opportunities";
                component.set("v.cardTitle", title);
            } else if (state === "ERROR") {
                var errors = response.getError();
                console.error(errors);
            }
        });
        console.log(recordUserName);

        $A.enqueueAction(action);
    }
})
4
  • Can you include the Apex controller code too, please?
    – Phil W
    Apr 2 at 19:21
  • 1
    The fact you call setCardTitle after fetchUser does not guarantee their callbacks return in the same order. Apr 2 at 21:53
  • @PhilW Just want you to know I’m new to the platform be didn’t realize it wouldn’t ping me with notifications. I’m just now seeing this and will edit this post with a response as soon as I’m in front of my computer
    – SethH
    Apr 3 at 23:28
  • @FelixvanHove Just want you to know I’m new to the platform be didn’t realize it wouldn’t ping me with notifications. I’m just now seeing this and will edit this post with a response as soon as I’m in front of my computer
    – SethH
    Apr 3 at 23:31

1 Answer 1

1

Calls to the server are asynchronous. This means that you can't guarantee the order in which the results will be returned; if getCurrentUserId finishes before getUser, you'll have a null value, as v.user will not have been set yet.

Instead, use Promises to control the order of operations. This requires a slight restructuring of your code. Since getUser and getOpenOpportunities don't have a dependency, you can call them first, then the other one afterwards.

In your controller:

Promise.all([helper.fetchUser(component), helper.fetchOpportunities(component)]
  ).then($A.getCallback(this, () => helper.setCardTitle(component)));

And then, your helper changes to return promises:

({
  fetchUser: function (component) {
    return new Promise($A.getCallback(this, (resolve, reject) => {
      var action = component.get("c.getUser");
      action.setParams({
        userId: component.get("v.recordId")
      });

      action.setCallback(this, function (response) {
        var state = response.getState();
        if (state === "SUCCESS") {
          component.set("v.user", response.getReturnValue());
          resolve();
        } else if (state === "ERROR") {
          var errors = response.getError();
          console.error(errors);
          reject(errors);
        }
      });

      $A.enqueueAction(action);
    }
    ));
  },

  fetchOpportunities: function (component) {
    return new Promise($A.getCallback(this, (resolve, reject) => {
      var action = component.get("c.getOpenOpportunities");
      action.setParams({
        recordId: component.get("v.recordId")
      });

      action.setCallback(this, function (response) {
        var state = response.getState();
        if (state === "SUCCESS") {
          component.set("v.Opportunities", response.getReturnValue());
          resolve();
        } else if (state === "ERROR") {
          var errors = response.getError();
          console.error(errors);
          reject(errors);
        }
      });

      $A.enqueueAction(action);
    }));
  },
  setCardTitle: function (component) {
    var action = component.get("c.getCurrentUserId");
    action.setCallback(this, function (response) {
      var state = response.getState();
      if (state === "SUCCESS") {
        var currentUserId = response.getReturnValue();
        var recordId = component.get("v.recordId");
        var recordUserName = component.get("v.user.Name");
        var condition = (currentUserId === recordId);
        var title = condition ? "My Open Opportunities" : recordUserName + "'s Open Opportunities";
        component.set("v.cardTitle", title);
      } else if (state === "ERROR") {
        var errors = response.getError();
        console.error(errors);
      }
    });
    console.log(recordUserName);

    $A.enqueueAction(action);
  }
})
5
  • Just want you to know I’m new to the platform be didn’t realize it wouldn’t ping me with notifications. I’m just now seeing this and will edit this post with a response as soon as I’m in front of my computer
    – SethH
    Apr 3 at 23:28
  • @SethH Answers should be in your Inbox. You may have accidentally dismissed the message (I do, too, sometimes). Just review this whenever you get a chance. I hope it helps you out.
    – sfdcfox
    Apr 3 at 23:45
  • Oh no they were in my inbox lol. I just assumed I'd get an email but I didn't get one until this afternoon. I'm about to test this now.
    – SethH
    Apr 4 at 2:16
  • Been trying to fix errors for an hour. Just keep getting?????? .then($A.getCallback(function() { helper.setCardTitle(component); })); (from salesforce not the parser)
    – SethH
    Apr 4 at 3:55
  • EUREKA. Debugged the error and no more null on username. Account names still aren't displaying lol but at least I solved this. Thanks 🙏🏼
    – SethH
    Apr 4 at 4:50

You must log in to answer this question.

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