[SalesForce] How is -tag-navigation to URLs and Objects done in Lightning (Summer’18)

The lost simplicity

The docs discourage the use of this pattern

<a href="/XXXXXXXXXXXXXXXXXX">Salesforce record ID (DON'T DO THIS)</a>

Instead we should

Use Navigation Events

Use one of the navigation events for consistent behavior across
Lightning Experience, Salesforce app, and Lightning communities.

  • force:navigateToList
  • force:navigateToObjectHome
  • force:navigateToRelatedList
  • force:navigateToSObject
  • force:navigateToURL

But this is NOT good enough!

Without a present href="" the usability is crippled in a dramatic way:

  • bookmarking the link is impossible
  • middle-click or control-click or right-click->popup to open in an other tab or window is impossible

I found the post here Why not use href="/id" or href="#/sObject/id/view" in Lightning?

Until Summer '18 I've used these patterns

#/sObject/id/view

But now with the new URL-scheme it does not work anymore. It simply stays on the given page.

Relative URLs worked earlier too, but now they reload the entire page instead of navigating to just the view in the given page. In other words: the single-page-app concept is broken and the navigation show the Summer'18 logo and it is very very slow.

Having a js-controller method funneling all the events also is overkill for my taste. A PERFECT navigation should work out-of-the-box in a 100% declarative way without touching into the guts of js-functions.

So how can we have it ALL?

  • present and working href (or alternative) to prevent the loss of bookmarking and rightclick-open-in
  • avoid reload of the page
  • if possible have all this done declarative

Has anyone a pattern or component for ALL that?

I'm thinking of writing my own "link component" now… but I want to avoid it (to avoid support, maintenance, etc). And I don't want to reinvent the wheel.

Update

Now with tears in my eyes, I've written my own compo for that… As far as I've quickly tested, it seems to work supporting all the above requirements. But I would like to get rid of it again, ASAP! I named it elfLCXLink.cmp and it looks like this:

<aura:component>
    <aura:attribute name="href"    type="String"      default="" access="global" />
    <aura:attribute name="onclick" type="Aura.Action"  />
    <a href="{!v.href}" onclick="{!c.onClick}">
        {!v.body}
    </a>
</aura:component>

Controller:

({
    onClick : function(cmp, evt, hlp) { 
        evt.preventDefault();
        var e = $A.get("e.force:navigateToURL");
        e.setParams({
            "url"               : cmp.get("v.href"),
        });
        e.fire();
        if(cmp.get('v.onclick')) {
            $A.enqueueAction( cmp.get('v.onclick') );   
        }
    }, 
})  

Usage Example

<c:elfLCXLink href="/lightning/r/Account/0010Y00000IMSUNQA5/view" >
    LEX Link
</c:elfLCXLink>
<br/>
<c:elfLCXLink href="/0010Y00000IMSUNQA5" >
    Aloha Link
</c:elfLCXLink>

Best Answer

From Summer18 I think one should use lightning:navigation component and the pagereference object that comes along with it .

The link here shows various possibilities within the lightning experience .

Lightning experience internally uses these navigation API so being consistent with the same for partners makes sense .

Here is a simple example

<aura:component implements="force:appHostable,flexipage:availableForAllPageTypes">
   <aura:attribute name="url" type="String"/>
   <aura:attribute name="pageReference" type="Object"/>
   <aura:handler name="init" value="{! this }" action="{! c.init }"/>
   <lightning:navigation aura:id="navService"/>
   <a href="{!v.url}">Link</a>
</aura:component>

Controller code

({
init : function(cmp, event, helper) {
    var navService = cmp.find("navService");
    // Sets the route to /lightning/o/Account/home
    var pageReference = {
        type: 'standard__objectPage',
        attributes: {
            objectApiName: 'Account',
            actionName: 'home'
        }
    };
    cmp.set("v.pageReference", pageReference);
    // Set the URL on the link or use the default if there's an error
    var defaultUrl = "#";
    navService.generateUrl(pageReference)
        .then($A.getCallback(function(url) {
            cmp.set("v.url", url ? url : defaultUrl);
        }), $A.getCallback(function(error) {
            cmp.set("v.url", defaultUrl);
        }));
   }
})

Also you can navigate using the navigate API methods as shown

<lightning:navigation aura:id="navService"/>
  <a href="{!v.url}" onclick="{!c.handleClick}">Link</a>
 <lightning:button label="Navigate" onclick="{!c.handleClick}"/>

controller function

({
handleClick: function(cmp, event, helper) {
    var navService = cmp.find("navService");
    // Uses the pageReference definition in the init handler
    var pageReference = cmp.get("v.pageReference");
    event.preventDefault();
    navService.navigate(pageReference);
  }
})

I don't have a pattern but if anyone manages to build a pattern use lightning:navigationAPI along with the various pagereference types .


(Update from Mark:)

There's a pretty big caveat with the new navigation component currently. (Docs link)

These navigation resources are supported only in Lightning Experience and the Salesforce mobile app. They’re not supported in other containers, such as Lightning Components for Visualforce, Lightning Out. This is true even if you access these containers inside Lightning Experience or the Salesforce mobile app.