Lightning Logger

In my Lightning components I always find logging and remembering how to navigate to urls using events to be an issue so I wrote this small utility base component that I then extend when creating new components. The base component share its helper with the subcomponents which allows for easy reuse of the utility functionality. The utility code provides both logging and various other utility functions such as navigating to other objects, presenting toasts etc.

Component definition of the base component is simple (note the {!v.body} which is key for abstract components to make sure the markup of child components appear):

<aura:component abstract="true" extensible="true">
 <aura:handler name="init" value="{!this}" action="{!c.doinit}" />
 {!v.body}
</aura:component>

Controller is likewise simple with basically only a callout to the helper to initialize a named Logger instance and store it in a variable called logger in the helper.

({
  doinit: function(component, event, helper) {
    const logger = helper.getLogger('SFLC_LightningHelper');
    logger.trace('Initializing LightningHelper');
    helper.logger = logger;
  }
})

To use it from another component you first extend the base component:

<aura:component implements="flexipage:availableForAllPageTypes,force:hasRecordId" extends="c:BaseComponent" controller="Foo_LCC">
  <aura:attribute name="recordId" type="Id" />
  <aura:handler name="init" value="{!this}" action="{!c.doinit}" />
  ...
  ...
</aura:component>

Then in the component controller initialization event create a named utility object (actually names the logger) and store it the “util” variable in the helper making it accessible using helper.util and the logger using helper.util.logger.

({
  doinit: function(component, event, helper) {
    // build utility
    const utility = helper.buildUtilityObject('MyComponent');
    helper.util = utility;
    
    // load data
    helper.loadData(component);
  }
})

From here on out you can simply use helper.util.logger.info, helper.util.logger.debug etc. to log for the component. All log messages are output using the named logger. The log level  which by default is NONE (meaning no output is output) is controllable using a URL parameter and loggers may be turned on and off using a URL parameter as well. Please note that the URL format used here doesn’t live up to the changes coming to Lightning URL’s in Summer ’18 or Winter ’18 (cannot remember which release).

Using the utility functionality can be done from controller and helper as shown in the loadData method using both utility functionality to invoke a remote action and to log:

({
  loadData: function(component) {
    // load data
    const helper = this;
    helper.util.invokeRemoteAction(component, 
      'getData', {'recordId': component.get("v.recordId")}, 
      function(err, data) {
        if (err) {
          helper.util.toast.error('Data Load Error', 'Unable to load data from server ('+ err +'). If the issue persists contact your System Administrator.', {sticky: true}); 
          return;
        }
        helper.util.log.debug('Received data from endpoint', data); 
      }
    )
  }
})

Zip file with Controller and Helper: BaseComponent

Beta of new Lightning Component Library included in Winter ’18

Was pleasantly surprised to see the beta of the new Lightning Component library being included in the Winter ’18 release. Quoting from the release notes (see page 533):


Find components more easily with the searchable component library. Preview the look and feel of components with interactive examples. To explore the new component library, go to https://<myDomain&gt;.lightning.force.com/componentReference/suite.app where myDomain is the name of your custom Salesforce domain. You can also continue to use /auradocs/reference.app in your org. And the Component Reference section in the Lightning Components Developer Guide continues to be available to you. …snip… Let’s look at some of the highlights. Gone are the days when you had to imagine how a Lightning component renders and behaves in your browser. Many components now have interactive examples and source code for common patterns. You can also learn about how a component is used through a list of examples.

The component library is really for the built in base components what the auradocs at /auradocs/reference.app is for your custom components and with the additional of all the new base components in Winter ’18 this is a nice addition.

Developing Salesforce Lightning Components that are visible at design time but not at runtime

So this can clearly be labelled as a “Lightning Lesson from the Field”. As you start to develop more complicated Salesforce Lightning applications – and why wouldn’t you – you as I have done start seeing great power in hidden components. By hidden components I mean components that contribute code or does “something” but which does not have a UI. Thes are very easy to do but have a big drawback as they are also invisible at design time making them near impossible to find the Lightning AppBuilder. To work around this I’ve come up with a hack that has proven itself very useful.

By using a combination of two simple attributes and 3 lines of JavaScript I can make the component markup visible at design time but invisible at runtime. Or if I need to toggle it on for runtime as well using an attribute I can set from the Lightning AppBuilder.

The video below goes more in depth and illustrates the concept. Happy coding.

Using component.find in Salesforce Lightning Components

When developing Salesforce Lightning Components you very often use the aura:id attribute on components to tag them and component.find to find them again. This works very well and is documented nicely in the documentation (Finding Components by ID). If however you tag a component using aura:id in an iterator you may not know how many resulting components will be on the page. The component.find method may return undefined (if no matching components), a component instance (if a single match was found) or an array of component instances if multiple components with a matching aura:id was found. This is fine but if you want to loop over any found component Javascript may give you a headache as the resulting variable may contain an array or an object instance. Hmmm… You can either using Vanilla Javascript to figure out whether it’s array (or cheat and use $A.util.isArray) and write code for the array case and code for the single instance case — or you can take the short route.

I always take the short route…

Say you had markup like this using an aura:iteration component to loop over a variable containg 0, 1 or many values.

<aura:iteration var="item" items="{!v.items}">
	<lightning:input type="checkbox" label="{!item}" aura:id="mycheckbox" />
</aura:iteration>

Contrast the approach using “isArray”

const cmps = component.find("mycheckbox");
if (!cmps) return;
if ($A.util.isArray(cmps)) {
    cmps.forEach(cmp => {
        // do stuff...
        cmp.set("v.checked", true);
    })
} else {
    // do stuff on the instance
    cmp.set("v.checked", true);
}

…to the approach of simply concatenating into an array… I find this much nicer, cleaner and it avoids the duplication of code between the single instance and array case. If I know there would always be at least one component it could even be done on a single line i.e. loose the undefined check on the second line. Javascript terse-ness heaven!!

const cmps = component.find("mycheckbox");
if (!cmps) return;
[].concat(cmps).forEach(cmp => cmp.set("v.checked", true));

Using preformatted HTML in a Salesforce Lightning Component

Had to output preformatted HTML richtext from a richtext field in a Lighting Component the other day. Looking through the documentation I found the ui:outputRichText component but it didn’t really work the way it’s mentioned in the documentation. Instead of the body of the tag containing the HTML the HTML had to be in the value-attribute as shown below.

<ui:outputRichText value="{!v.data.Contact.Bio}" class="bio" />

The “bio” CSS class I added is to actually apply the formatting I need. Although the HTML contains the HTML tags the CSS on the Lighting Pages stripped the UL and LI formatting I needed so I had to manually add that back. The CSS I applied is below.

.THIS .bio {
    margin-left: 15px;
}
.THIS .bio ul ol {
    margin-top: 10px;
    margin-bottom: 10px;
}
.THIS .bio p {
    margin-top: 10px;
    margin-bottom: 5px;
}
.THIS .bio li {
    display: list-item;
    list-style-type: disc;
}

Salesforce Lightning Design System (SLDS) Activity Component and z-index

For the Lightning Components I’m developing for a customer I’m using the activity timeline component to show a chronologic timeline of “stuff”. However when I added the markup to my Lightning Component and ran it inside Salesforce the vertical bars were missing. What to do? Crack open the Chrome Developer Tools and inspect – but hey! Then the bars were there… Close Developer Tools and the bars were gone again. Hmmm… Seems to be a viewport height issues. But then again not…

After quite a lot of tinkering I figured out that the issue was actually caused by a z-index issue of the layer showing the bar. I had to add the below CSS to my styling. Please note that I’m using the “event” sprites and coloring. But the most important thing to pay attention to here is the z-index of the :before psudo class for the slds-timeline__media classes and the slds-media__figure.

.THIS .slds-media__figure {
	z-index: 2;
}
.THIS .slds-timeline__media--event:before {
    background-color: #a9a9a9;
    z-index: 1;
}
.THIS .slds-timeline__media--event:before {
    background-color: #ff6600;
    z-index: 1;
}

YMMV…

Salesforce Lightning Components and image dependencies

I am developing some Salesforce Lightning components at the moment as while Lightning Components are great they have a major drawback in my mind. Some background first… Salesforce Lightning is our “new” component based UI based on HTML / Javascript and components are automatically mobile ready and responsive. A Lightning Component is not a single “thing” but rather a folder with stuff that is a number of files named using a predefined format. The component name is the name of the folder – e.g. MyComponent. The actual markup goes in the component file called MyComponent.cmp. Besides the markup there is the client side controller (MyComponentController.js), CSS styling (MyComponent.css) and that’s basically it. There are few more potential files but they are not important for this post. All is well described on the web. What’s not included in the component is graphics that may be used by the component.

The way graphics are added to components a either by using the sprites supplied with the Salesforce Lightning Design System (SLDS), by using custom graphics or you can use the classic icons which are supplied by Salesforce. The latter are really not ideal as do not look nice as they look old and the colors cannot be easily changed. The issue with using custom graphics or the SLDS sprites is that the resources are kept in Salesforce as static resources which is great for performance as they are automatically loaded through our CDN but they are outside the Lightning component. So now a component is no longer self contained but has dependencies to other metadata elements. To make it even worse these dependencies cannot be declared for the component that the normal dependency detection doesn’work eg. changesets will not detect the dependency. Not good…

To solve this I’ve started to use base64 encoded images as they can easily be used in img-tags and may be embedded in either markup or in JavaScript. An img-tag can use base64 instead of an image reference as below. This solves the above issue as images are now fully contained in the component code or markup so no external dependencies are required. An easy solution to a complicated problem.

&ltimg src="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABQAAAAUCAYAAACNiR0NAAAABHNCSVQICAgIfAhkiAAAAAlwSFlzAAAL" />

This

On Mac (and Linux probably) getting an image as a base64 encoded image for easily done using the base64 command and I normally cut lines to 80 characters as the developer console doesn’t handle looooooong lines well. Combining with sed can add the quotes and pluses to make it easier to get it into Javascript. A little tweaking if required but it is faster.

base64 -b 80 -i ./picture1.png
base64 -i Downloads/gold_star.png -b 80 | sed -e 's/^(.*)$/"1"+/'