lightningStar

Input Rating Lightning Component

The Lightning Component framework enables developers to create a wide range of reusable components. The <ltng:require> component that is generally available in Summer ’15 makes it much easier for developers to use JavaScript and CSS in their components in a reliable way. This post explores a custom Lightning Component for applying star ratings to objects.  The jQuery raty plugin is used to simplify the rating interactions.

Input Rating Lightning Component Usage

The component itself renders the stars for the rating. It can then be used by other components or apps.  Here is an example of it being used in a demo app with the Lead object. The user just clicks/touches the number of stars to specify the rating value.

A screen capture of the component with input rating, company, first name, last name, email inputs

The code in the demo app that uses the rating component is straightforward. It defines a Lead instance and binds to ui:inputs.  The form portion is as follows:

The <c:inputRating> creates an instance of the custom rating component and specifies which field the rating value should be bound to via the value attribute. In this case, it is a custom number field on the Lead object.  The cool thing about doing it this way is that the framework’s two way binding will automatically set the number of stars to the correct value for an existing Lead if it were loaded from the DB and, likewise, any changes to the number of stars selected will automatically (and instantly) be reflected wherever else the Rating__c field is used. This includes the c.save event handler that processes the form input.

Input Rating Lightning Component Source

Input Rating Rating Component File

The markup in the component file (inputRating.cmp) is as follows.

The actual HTML is only a single div which is then converted to the star input by the raty plugin, using JavaScript.

The <ltng:require> component specifies the scripts that need loading, a css file to load, and a controller event handler to call after the scripts have finished loading. The <ltng:require> component loads the scripts in the order that they are specified. In this case that is important because the raty JS file is dependent on the jQuery JS file. If there were no dependencies they could safely be specified in separate <ltng:require> tags which would allow them to be loaded in parallel.

Another nice feature of the <ltng:require> component is that if you do have multiple instances of the same component it will only load the specified JavaScript files once. In fact, it only loads them once across all components.

Input Rating Component jQuery Object

The code to create the actual jQuery raty instance from the div resides in the helper.  I left the raty config very simple. There are many more advanced configurations that could be used to change, for example, the styling and the range of allowed values (refer to the raty docs).

The component’s find method is used to get the element itself to pass to the jQuery ($) function. The reason for this versus just using a typical jQuery id selector or class selector is that there could be multiple instances of the component on a page at one time, but only the one contained in the current instance should be selected.  Using component.find limits the scope to the current instance.

The raty object is initialized to have the value of the field passed in and it defines a callback to set the field’s value whenever the number of stars selected changes. The framework’s two way binding takes care of the value being in sync and anything that depends on the value being updated and rerendered if necessary.

Input Rating Component Rendering

I added one more bit of complexity to the component to handle the case where the <ltng:require> may have finished loading the scripts, but the component was not yet rendered. I’m not sure how often this would happen in practice, but there wasn’t any documentation stating it couldn’t happen. If it were to happen the jQuery would fail as it would not find the div element in the DOM since it had not yet been rendered. To combat that, I implemented a renderer (inputRatingRenderer.js) and defined it’s afterRender method to simply call to the helper.

I also added an attribute “ready” that is set in the afterScriptsLoaded event handler.  In the helper, the jQuery only executes if “v.ready” is true.  This prevents the jQuery from executing in the other case — when the helper is called by the afterRenderer firing before the afterScriptsLoaded.

This pattern of setting and checking the “v.ready” was adapted from an earlier unmanaged package dependency management component that was part of an SFSE answer.

More on Lightning Components

This post showed how the inputRating component could be used with a Lead object, but it could be used in most scenarios where inputs are used. The source for the inputRating component is available in this gist. To learn more about the Lightning Component framework check out the Lightning Components Developer’s Guide and the excellent Lightning Components Trailhead module.