1

I need to store some simple string values during a users session. I don't need to store this in a cookie or local storage just in a simple globally accessible place. If the user leaves the page it's OK to lose the data.

Sifting through all the documentation I can not locate anything that might help.

Or, alternatively ... is there a way to get the current user's ID and the ID of the current case deep down in a hierarchy of components. I've a component that is nested about ten levels deep and I need these values.

One approach I'll try is to fire an event at the top level to broadcast the needed ids and catch the event further down the chain but this can only work if all nested components exist in the markup (e.g. it won't work for dynamic components). Thoughts?

  • Platform Cache is also an option - it is available to customers with Enterprise Edition orgs and above. The following editions come with some default cache space: Enterprise Edition (10 MB by default); Unlimited Edition (30 MB by default); Performance Edition (30 MB by default). – Mark Pond Jun 13 '18 at 1:54
  • Thanks Mark. Very interesting yet I'm a developer with a developer edition. – Bryan Jun 13 '18 at 2:13
  • In a developer edition org, on the Platform Cache page, you can request the trial of the feature to get it enabled. Just be aware that if your customer / company doesn't have one of those editions, Platform Cache isn't included (that relatively minimal initial amount) and must be purchased. – Mark Pond Jun 13 '18 at 2:37
2

To get the ID of the currently viewed record, use implements="force:hasRecordId" on your component. To get the user's Id, use {!$CurrentUser.Id}. More generically, if you want to store stuff, sessionStorage and localStorage is the best you're going to get for storing global data without some extra effort. However, if you wanted to, you could make a global storage component.

This is the absolutely minimum, no frills, no security, no error handling, no singleton model, etc. Do not use this in production code as-is. It's simply not meant to handle all the possible scenarios that might come up. Do, however, use it to understand why creating this implementation is likely problematic in the first place; it would be notoriously difficult to get everything working just right.


c:globalDataSet.evt

<aura:event type="APPLICATION" description="Sets a global value for later retrival">
  <aura:attribute name="data" type="Object" />
  <aura:attribute name="name" type="String" />
</aura:event>

c:globalDataGet.evt

<aura:event type="APPLICATION" description="Gets a global value">
  <aura:attribute name="callback" type="Function" />
  <aura:attribute name="name" type="String" />
</aura:event>

c:globalStorage.cmp

<aura:component>
  <!-- note: should ideally only be used once in the entire hierarchy -->
  <aura:handler event="c:globalDataGet" action="{!c.getData}" />
  <aura:handler event="c:globalDataSet" action="{!c.setData}" />
  <aura:attribute name="data" type="Map" access="private" />
</aura:component>

c:globalStorageController.cmp

({
  getData: function(component, event) {
    var params = event.getParams(),
        data = component.get("v.data");
    params.callback(data.get(params.name));
  },
  setData: function(component, event) {
    var params = event.getParams(),
        data = component.get("v.data");
    data[params.name] = data;
    component.set("v.data", data);
  }
})

Note: This is obviously only a very basic implementation. A full-featured implementation would be able to detect multiple instances and share the data efficiently across those instances. As written, you only need one instance of this component anywhere on the layout, and all components can dispatch events to request or store data.

  • Thank you very much for such detail. I can see why this is both an interesting approach and could open up many a rabbit hole. I appreciate your efforts to help and your knowledge of SF. I've another approach and will post it below. Comments and critiques are most welcome. Oh. I tried to $CurrentUser without luck and I've spent a day or so trying to get session or localstorage to work, without luck. – Bryan Jun 13 '18 at 1:48
  • For user information I found this post salesforce.stackexchange.com/questions/100951/… With the solution of making a server side call. – Bryan Jun 13 '18 at 2:13
  • @Bryan It's {!$CurrentUser.Id}-- you need to pay attention to capitalization and all that. Try copying this: <aura:application>{!$CurrentUser.Id}</aura:application> and preview it in your org. – sfdcfox Jun 13 '18 at 2:15
  • The syntax for current user is var userId = $A.get("$SObjectType.CurrentUser.Id"); – Bryan Jun 13 '18 at 2:27
  • @Bryan Oh? I wonder if it was always that way, or if they changed it. It's not officially in the docs, far as I can tell. – sfdcfox Jun 13 '18 at 2:30
2

One approach that is a hammer but works for me is to pass a global object aroundUI of nested components

Each component is given a reference to a global object and each is free to modify this object. In this demo the outer and InnerInner components both have update buttons that change a property in the global. Because they are bound up and down the chain the values are shared.

Outer.cmp

<aura:component implements="flexipage:availableForRecordHome,force:hasRecordId" access="global">
    <aura:attribute name="globals" type="Object" default="{UserId:'1'}"/>
    <aura:handler name="init" value="{!this}" action="{!c.doInit}" /> 

    <div style="border: 1px solid black; padding: 2rem">    
    <h2>Container</h2>
    <lightning:button label="update" onclick="{!c.update}"/>
    <div>BetaComponent</div>
    <p>
        globals.UserId = {!v.globals.UserId}
    </p>
    <!-- pass the global down to the inner component -->
    <c:BetaInner propInner="{!v.globals}"/>
    </div>
</aura:component>

OuterController.js

({
    doInit: function(component) {
        var globals = {'UserId': '123', 'CaseId' : '0987'};
        component.set("v.globals", globals);
    },
    update : function(component) {
        var newId = Math.floor(Math.random() * Math.floor(10000));
        var globals = {'UserId': newId, 'CaseId' : '0000'};
        component.set("v.globals", globals);
    }
})

Inner.cmp

<aura:component >
    <aura:attribute name="propInner" type="Object"/>

    <div style="border: 1px solid black; padding: 2rem">

    <h3>Inner component</h3>
    <p>Get user from propInner.UserId = {!v.propInner.UserId}</p>   

    <!-- pass the global down to the inner component -->
    <c:BetaInnerInner propInnerInner="{!v.propInner}"/>
    </div>
</aura:component>

InnerInner.cmp

<aura:component >
    <aura:attribute name="propInnerInner" type="Object"/>

    <div style="border: 1px solid black; padding: 2rem">
    <h4>Inner Inner component</h4>
    <lightning:button label="update" onclick="{!c.update}"/>
    <p>Get user from propInnerInner.UserId = {!v.propInnerInner.UserId}</p>   
    </div>
</aura:component>

InnerInnerController.js

({
    update : function(component) {
        var newId = Math.floor(Math.random() * Math.floor(10000));
        var globals = {'UserId': newId, 'CaseId' : '0000'};
        component.set("v.propInnerInner", globals);
    }
})

UPDATE: Thanks to this blog http://sfdcmonkey.com/2018/01/08/display-current-user-information/ there is a simple way to get the current user id

  var userId = $A.get("$SObjectType.CurrentUser.Id");
  • Having used the above for a while here is some news. The shared global object lives until the page is refreshed. The shared global object is shared across multiple instances of the same component. (When I click on a Case in the case list my components are used on the case record page. Each time I select a Case a whole new set of components are created. The old ones are not destroyed. They all share the same global object. See salesforce.stackexchange.com/questions/223806/… – Bryan Jul 4 '18 at 4:26

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.