(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.
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!
Best Answer
The empty arguments is a bit strange - a side effect of the way your renderer method is invoked by Lightning (Aura Framework) - but if you console.log(cmp) and console.log(helper) you will see that they are in scope and available.
You do not have to use a Helper at all unless you have common code you want to be able to call from other renderer (or controller) methods.
Implementing render(), rerender(), etc allows you to take over the DOM generation and update process entirely or (what I do more often) is to let Lightning markup do some of the work and then custom javascript (often 3rd party libs) fill in the blanks.
Even better in many cases is to delegate all of the rendering work to Lightning and leverage its powerful data binding {!v.something} capabilities with auto update (even bidrectional if you need that). So instead of creating a renderer you can have your .cmp use {!v.something} expressions and just have your client side controller update the underlying model/attribute values and Lightning will automatically (and very efficiently) rerender the subregions from your cmp that are impacted.
I often combine all of the above to achieve the best balance.