[SalesForce] How to use jQuery (or any JS lib) in initial post rendering of Lightning Components

The Lightning Developer's Guide, around page 100 in the Accessing the DOM After Rendering section, states:

If you want to use a library, such as jQuery, to access the DOM, use it in afterRender().

I've created a Renderer:

({
    afterRender : function(component) {
       this.superAfterRender();
       console.log(component.isRendered()); // is evaluating to true
       console.log($); // causes error overlay because $ is undefined
    }
})

My app includes the static resource:

<script src="/resource/jquery" type="text/javascript"></script>

I can confirm that the jquery JavaScript resource file is retrieved by the browser by monitoring the traffic in the Chrome developer console and I can also use the jQuery or $ vars in the Chrome console after the page loads.

However, if I try to access the jQuery in the afterRender function I get the error overlay ("Looks like there's a problem") with a message:

Error while running aura://ComponentController/ACTION$getApplication:{"name":"myNameSpace:myApp"} : $ is not defined

I suspect I'll be fine to use jQuery after the app has loaded the first time, but I want to use it on the initialization.

There's a similar question on the developer boards here.

Best Answer

(Cross-posted from the answer on developer.salesforce.com)

Hi Peter,

Polling isn't really ideal as the timing may vary depending on the device, network, etc., and between standalone apps and the Salesforce1 Mobile App. Using a loader such as RequireJS works well, and a few folks have written samples that use this. Here's an unmanaged package that includes events, components, static resources, and a sample app that uses RequireJS to load jQuery and Bootstrap:

https://login.salesforce.com/packaging/installPackage.apexp?p0=04tB000000011BS

Because it's unmanaged, you will need to change the namespace from aotp1 to your own. Once you've done that you can access the test app with a URL similar to this:

https://XXX.lightning.force.com/yyyy/requiresTestApp.app

You can also use Setup to add the requiresTestTab to S1. It's the same as the standalone app, just in a component that can be accessed from the "stage left" menu in S1. These components demonstrate using a namespaced version of Bootstrap, along with setting up Bootstrap and jQuery via different ways. They are integrated via attributes, events, etc. jQuery selectors are constrained to the component, something that's important to consider as components ≠ full-page apps. A jQuery plugin to do this automatically is a good candidate for another sample.

Screenshot of requiresTestTab in S1

We're working on how to best support this in the product. In the meantime samples such as this can help many users. If you improve on this, or find that lighter weight loaders such as headLoad work well, I'd be interested in hearing more.

Updates as of 10/30/2014:

I've updated the sample to include the script loading in the requires component, as Peter suggested. Included are:

  • The requires component is now defined as follows:
<aura:component>
    <aura:attribute name="baseUrl" type="String" default="/resource/"/>
    <aura:attribute name="styles" type="Map"/>
    <aura:attribute name="scripts" type="Map"/>
    <aura:attribute name="deps" type="Map"/>
    <aura:attribute name="initScripts" type="Aura.Action"/>
    <aura:registerEvent name="requiresReady" type="aotp1:requiresReady"/>
    <aura:handler name="init" value="{!this}" action="{!c.init}"/>
</aura:component>
  • The requiresTest2 component uses the requires component as follows (note the ready flag used to indicate that the component has been initialized):
<aura:attribute name="ready" type="Boolean" default="false" description="Used to check..."/>

  • The requiresTest2 helper now has an initHandlers function that is called from the requiresReady event and the renderer. The ready flag mentioned above is used to check whether to proceed with the init. This is necessary because the loading order can vary depending on the container, for example the Lightning app vs. the Salesforce1 Mobile App tab.

  • The requiresReady event is now COMPONENT scoped, and includes the objects returned by the requirejs callback, using the names specified in the attributes.

Version 1.2 installation URL:

https://login.salesforce.com/packaging/installPackage.apexp?p0=04tB000000011BX

As with any samples, no guarantees are made, but I am interested in feedback or improvements!