Gotcha! Components in Shared regions don’t receive the recordId

This is for Shared Regions (like header, navbar, footer) in the Community app builder:

Community Builder Shared Regions
Community Builder Shared Regions

Today I learnt that if your component implements force:hasRecordId then it won’t get a record ID, even if you’re on an Account page for example.

Secondly – these shared regions are not re-rendered during navigation – which is obviously great for performance reasons 🙂

Why would a component in the shared areas want the recordId?

My use case for this is pretty simple- my Navigation Bar has some shortcuts to specific Products, so if the user ends up on the Product page (either by clicking directly or from a Search), then I want my nav bar to highlight that we’re now looking at that Product!

So, how can we workaround this limitation and have a component in the shared region get the recordId?

Well you’ll need to listen to the forceCommunity:routeChange event.

<aura:component implements="forceCommunity:availableForAllPageTypes,force:hasRecordId">
    ...
    <aura:handler event="forceCommunity:routeChange" action="{!c.handleRouteChange}"/>
    ...
</aura:component>

However, how do you then get the recordId?

Well there’s a couple of options:

1 Parse the window.location.path to extract it

The simplest solution (and very hacky as we’ll see) is to parse the window.location url to get the current object Id.

Now the hacky part is to find the Id from the url because it’s changed recently from:

https://myorg.na54.force.com/mycommunity/s/account/001o000000wFyKxAAK

to:

https://myorg.na54.force.com/mycommunity/s/account/001o000000wFyKxAAK/adams-keith

Notice the Object Name appended! So how can we handle this? Well, I haven’t figured out a 100% bullet proof solution yet because who know how it will change next! My solution for now works around the fact that there’s always a /s/ in the url:

({
    handleRouteChange : function(component, event, helper) {
        var recordId,
            pathParts = window.location.path.split('/');
        for (var i = 0; i < pathParts.length; i++) {
            if (pathParts[i] === 's') {
                recordId = pathParts[i + 1];
                break;
            }
        }

        cmp.set('v.recordId', recordId);
    }
})

pro’s
– Fast and simple fix to make

con’s
– Who know when it’ll break!?

2 create a separate component which fires data to your shared component

In this solution we create a separate component which lives on the pages which display a record and fire a custom event which your navigation bar listens to.

So first create a custom Lightning application event – I’ll call my viewingRecord

<aura:event type="APPLICATION">
    <aura:attribute name="recordId" type="String"/>
</aura:event>

Then create a new custom component which will fire this:

<aura:component implements="forceCommunity:availableForAllPageTypes,force:hasRecordId">
    <aura:handler event="forceCommunity:routeChange" action="{!c.handleRouteChange}"/>
    <aura:registerEvent name="viewingRecord" type="c:viewingRecord"/> 
</aura:component>

and for its controller simply add:

({
    handleRouteChange : function(component, event, helper) {
        var appEvent = $A.get("e.viewingRecord");
        appEvent.setParams({ "recordId" : component.get('recordId') });
        appEvent.fire();
    }
})

Finally you’ll need to update your component that lives in the Shared Region to handle this event:

<aura:component implements="forceCommunity:availableForAllPageTypes">
    ...
    <aura:attribute name="recordId" type="String" />
    <aura:handler event="c:viewingRecord" action="{!c.handleViewingRecord}"/>
    ...
</aura:component>

And in its controller the implementation for the event would be:

({
    handleViewingRecord : function(component, event, helper) {
        var recordId = event.getParam('recordId');
        component.set('recordId', recordId);
        // do anything you need now you have the recordId
    }
})

pro’s
– A lot more reliable – no url parsing so you’ll be sure you got the recordId

con’s
– Needs an extra component which can either be in your Content Layout or has to be added by the User (yuck!)
– However, your user may not use your Content Layout and if they don’t then…
– if the user forgets to add it then you’re back to square one 🙁

The future?

After discussing with some of the Lightning team there’s a couple of proposals that might help with this:

  • Adding more data to the forceCommunity:routeChange event – for example which page you’re now on
  • Don’t allow components which implement force:hasRecordId to be dropped into shared regions

Leave a Reply