11

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.

4 Answers 4

11

(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!

3
  • 1
    Thanks Skip. I have this working, but is there a version of the requires component that allows other components to specify JavaScript files in a similar fashion as the CSS styles? Currently, it looks like each individual component is responsible for loading its own JavaScript instead of specifying the file it needs loaded as an argument to the requires component. Example: The 'requiresTest2Helper.js' has initScripts in it. It looks like every component that wants js file(s) will have to implement that. It would be ideal if the components only had to implement the initHandlers. Oct 25, 2014 at 14:52
  • 3
    @PeterKnolle - We've had non-requirejs-based versions that do this, but the requirejs usage pattern made it easier to let the component do it. That being said, I'm looking into it and will post an update.
    – Skip Sauls
    Oct 29, 2014 at 18:10
  • 1
    I've updated the sample to include the script loading in the requires component, as Peter suggested. Included in the update:
    – Skip Sauls
    Oct 30, 2014 at 16:05
4

In all documentation it states

<ltng:require scripts="/resource/jQuery1120" afterScriptsLoaded="{!c.afterScriptsLoaded}"/>

But you need to add / after the resource name

<ltng:require scripts="/resource/jQuery1120/" afterScriptsLoaded="{!c.afterScriptsLoaded}"/>
2

I've noticed that there is ltng:require component in auradocs: https://cs11.lightning.force.com/auradocs/reference.app#reference?descriptor=ltng:require&defType=component and usage is:

<ltng:require 
    scripts="/resource/styles/js/jquery.min.js,
             /resource/styles/js/jquery.dataTables.min.js,
             /resource/styles/js/calendar.js"
    afterScriptsLoaded="c.onInit"/>

But there is no reference in Ligtning Comp Dev Quide. It seems safe to use what is available in auradocs.

3
  • 1
    The support level is still PROTO which is defined as "PROTO—The component is still in development and is unsupported. This is the default support level." You can see PROTO in the upper right hand corner of the ltng:require component's doc page. You can see definitions of the support levels at "/auradocs/reference.app". Mar 14, 2015 at 2:58
  • 2
    Fyi, we recently added support for 'ltng:require'. Please see link for details. Mar 18, 2015 at 18:10
  • @Diana Widjaja Myerscough, Thanks for this update. Good to know that this component is officially supported.
    – Natallia
    Mar 18, 2015 at 21:53
2

To manage such case, you can simply use a master component , an attribute isLoaded & change handler on sub-components

Master.cmp

<ltng:require 
    scripts="/resource/styles/js/jquery.min.js"
    afterScriptsLoaded="c.afterScriptLoaded"/
<aura:attribute name="isMasterLoaded" type="Boolean" default="false" />
<c:ChildCmp canBeLoaded="{!v.isMasterLoaded}" />

Master.controller.js

afterScriptLoaded: function (component,event,helper) {
     component.set('v.isMasterLoaded',true);
}

Child.cmp

<aura:handler name="change" value="{!v.canBeLoaded}" action="{!c.doYourInit}"/>
<aura:attribute name="canBeLoaded" type="Boolean" default="false" />

Child.controller.js / helper / renderer

if (component.get('v.canBeLoaded') === true )
{
 /// Do whatever u need
}

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .