Saturday 28 November 2015

Context is Everything

Context is Everything

Context title

You Are in a Maze of Twisty Passages, All Alike

When building applications around Lightning components on the Salesforce platform, there comes a time when you need to know where you are - in Salesforce1 or the Lightning Experience for example. Winter 16 upped the ante by allowing Lightning components to be embedded in Visualforce pages. I was expecting there to be a mechanism to get at this information via the Lightning component framework, but unfortunately that turned out not to be the case, so I had to spend some time investigating.

Desperately Seeking Context

My problem was how to figure out from inside a Lightning component whether I was executing in:

  • Salesforce1
  • Lightning Experience (LightingX)
  • Visualforce inside Salesforce1/LightningX
  • Visualforce in Salesforce Classic

Lightning Detector

Looking through the docs, there are a couple of events that are only available to components executing in Salesforce1/LightingX:

  • force:showToast
    This displays a message in a popup (or really a popdown, as it appears under the header at the top of the view)
  • force:navigateToURL
    This allows navigation to a URL from a lightning component

The docs state that it these methods are only available in Salesforce1, but as far as I’ve been able to tell, LightningX is pretty much Salesforce1 for the desktop. 

In my JavaScript controller or helper, I can attempt to instantiate the event and based on the success or failure, deduce whether I am in the Lightning context: 

isLightning: function() {
    return $A.get("e.force:showToast");
}

Mobilize

The availability of the above events tells my component if it is executing in Lightning, but not which of Salesforce1 / LightningX is the container. The only way I’ve found to reliably detect this is to use the blunt instrument that is the user agent, 

I’ve tested on an iPhone, iPad and Android phone, both for the HTML5 and installed application versions of Salesforce1, and the user agent string always contains the word ‘mobile’. However, when I am running LightningX on the desktop, this is not the case.

Note that this is by no means exhaustive testing, so if you are considering using this technique make sure to verify this behaviour on your target devices.

The controller/helper can detect mobile based on the presence or absence of mobile in the user agent as follows: 

isMobile: function() {
    var userAgent=window.navigator.userAgent.toLowerCase();
    return (-1!=userAgent.indexOf('mobile'));
}

Visualforce

I’ve found that this scenario causes the most confusion, as the assumption is that as code from a lightning component is executing, the context must somehow switch to Lightning while that is happening. A better way to think about this is in terms of the container. In Salesforce1 and LightningX, the containing application is built with Lightning components, whereas when a Lightning component is embedded in a Visualforce page, the page is the container.

The ability to detect if a Visualforce page is embedded in a Salesforce1 application has been around for a while now, and it is equally applicable to LightningX - check if the sforce and sforce.one objects are present. I can detect this in my controller/helper as follows:

hasSforceOne : function() {
    var sf;
    try {
        sf=(sforce && sforce.one);
    }
    catch (exc) {
        sf=false;
    }
     
    return sf;
}

Putting it all Together

Going back to my list of scenarios, from my lightning component I can detect each of these using the functions defined earlier  as follows:

  • Salesforce1

        isLightning() && isMobile()
     
  • Lightning Experience (LightingX)

        isLightning() && (!isMobile())
     
  • Visualforce inside Salesforce1/LightningX

        (!isLightning()) && hasSforceOne()
     
  • Visualforce in Salesforce Classic

        (!isLightning()) && (!hasSforceOne())

The Future

While these mechanisms are the best I’ve been able to do with the available tools, Salesforce will probably add something to the Lightning component framework that makes them redundant. When this happens, if you’ve kept the functionality in the methods I’ve shared above, you can simply update these to delegate to the framework rather than figuring it out for themselves. 

Related Posts

 

Saturday 14 November 2015

Trailhead in the Wild

Trailhead in the Wild

Screen Shot 2015 11 14 at 16 54 32

Available, generally 

Trailhead is out of beta and generally available, so if you’ve been holding back in case it disappeared (pretty unlikely given the dev zone at DF15 was built around it) you can now jump in with both feet. It also has an updated UI, which feels a lot faster to me, even on what passes for an internet connection to my home!

Find what you need faster

Its now easier to find the right content for you - after clicking on the ‘Learn Trailhead for Free’ button, you are presented with a popup dialog where you choose between Admin, Developer or Business User:

Screen Shot 2015 11 14 at 16 51 51

of course the correct approach to Trailhead is to take everything, so this is really more a case of deciding the order in which you want to cover things!

Trailhead has also been incorporated into the search functionality, so if, for example, you search for ‘Lightning’ you’ll get details of the 30 trails with Lightning content - perfect if you are looking to learn about a specific feature of Salesforce.

Look mother, I’m dancing!

Its now even easier to seek and get the attention you deserve for your Trailhead accomplishments.

After passing a step you get some nicely styled flattery and the option to share this milestone with your social media followers.

Screen Shot 2015 11 13 at 21 18 17

Gain a badge and the ante is upped considerably - not only can you ram this down the throat of the badge-poor on social media:

Screen Shot 2015 11 13 at 21 25 57

but you can also post this to your LinkedIn profile and thus receive further connection requests and messages from recruiters desperate for Salesforce candidates:

Screen Shot 2015 11 13 at 21 27 10

Here’s my latest badge on my LinkedIn profile (Look, there’s my Technical Architect cert, how did that get in there? Oh well, best leave it in for now!).

Screen Shot 2015 11 13 at 21 28 46

At the moment it looks like you can only add new badges to LinkedIn, something that LinkedIn are probably okay with, given that they’d be looking at the flood of over 250,000 badges that have been earned to date!

All I want for Christmas

So what does the future hold for Trailhead? Even if I knew, one of the many NDAs that I’ve signed over the years would no doubt preclude me from talking about it. What’s the first rule of the future of Trailhead?

Given how successful and high profile Trailhead has been to date, I think it's safe to assume we’ll continue to see the content expanded and the experience improved. Here’s a few things that I’d really like to see, and be assured that I have given no thought to how expensive or difficult they might be to achieve:

  • Private trails
    I’d imagine that pretty much every Salesforce customer and partner would find this useful - the ability to create trails around your own custom processes and applications, along with exercises, verification and badges would be a great benefit when on-boarding new staff.
  • Groups of users
    Obviously I’d use this to pit my colleagues against each other to see who could upskill on a particular area the fastest. I think I’d have a lot of fun with this.
  • API Access to Trailhead Profiles
    I’d use this to build a leaderboard for my company, to shame the badge-poor give new hires something to aim for. Then I’d probably use it for evil, so oauth would be a good authorisation mechanism as users could easily revoke my access.
  • Fantasy Trailhead
    Team Managers would pick teams of community users and get points as they gained Trailhead badges. Maybe they would lose points if their team didn’t gain badges quickly enough. Gamification squared if you will. It would also open up Fantasy Fantasy Trailhead, where you would pick teams of Team Managers, and so on, for ever.

Still free, as in beer

Shutup

Nothing down and nothing a month.

Saving the best until last

When you open the Trailhead home page and scroll down, you’ll see my face over the Developer Trails link, and I think we can all agree it doesn’t get any better than that.

Related Posts

  

Sunday 1 November 2015

Reading QR Codes in Salesforce1 Revisited

Reading QR Codes in Salesforce1 Revisited

Overview

Back in 2014 I wrote a blot post around reading QR codes in the Salesforce1 application to automatically navigate to a record. At the time, Salesforce1 did not have a custom URL scheme to allow it to be easily opened from an external application. That all changed at the beginning of 2015 with the launch of the Salesforce1 Mobile URL Schemes.

With a custom URL scheme, there’s no longer any need to process a picture of the QR code in the Salesforce1 application. This improves the user experience for a couple of reasons:

  • The original process of take a picture, see if it looks good enough and then try to process it can be time consuming. 
  • Even with what appears to be a good picture, I’ve always found the processing to be quite slow and rather hit and miss.

A dedicated QR scanner application is much less picky about the picture quality and typically processes the code in under a second, so this seems to be the obvious way to go.

Scanners and Custom URL Schemes - Will They Ever Get Along?

Unfortunately, many scanner applications don’t handle custom URL schemes and when they see a URL that doesn’t start with http/https, throw an error.  One way to work around this is to use a URL shortener - TinyURL, for example will convert a URL with a custom scheme to one with an http scheme. This isn’t a great solution though, as I’d need to integrate with the URL shortener when generating my QR code and it introduces an additional HTTP request to the shortening service. When you are working in mobile world, the last thing that you want is to introduce additional requests!

Luckily, some scanner applications do support custom URL schemes - I used Scan when preparing this post.

Generating a QR Code

There are a few ways to generate a QR code. In the past I’ve used the Google Infographics service, but that has been deprecated for over three and a half years now so is highly likely to stop working. The most popular replacement for this is GoQR.me, which works in much the same way, generating a QR code via an HTML image element. 

The URL that the code represents needs to follow the Salesforce1 custom URL scheme to navigate to a record’s view page:

salesforce1://sObject/<id>/view

I’ve created a simple Visualforce page to generate the QR code for an Account record.

<apex:page standardController="Account">
  <apex:pageBlock title="QR Code">
    <p style="padding-bottom: 10px">
       Scan the code below on your mobile device to open the account record in Salesforce1
    </p>
    <apex:image
          value="https://api.qrserver.com/v1/create-qr-code/?size=150x150&data={!URLENCODE('salesforce1://sObject/' + Account.Id + '/view')}" />
  </apex:pageBlock>
</apex:page>

 Navigating to this page with the ID of an existing account renders the following page:

Screen Shot 2015 11 01 at 08 08 22

Scanning the Code

Scanning this with a QR code scanner application that supports custom URL schemes navigates to the record view, as shown the video below. Note that I need to be logged into the organisation that the record belongs to in order to view it.

This video shows how much better using a dedicated scanner app is versus taking a picture and processing it - as long as I’m pointing the camera in the direction of the QR code, the app barely has time to start up before it has locked onto the code and is processing it.

Related Posts