2

I'm having trouble accessing my static resource (a js lib) in my controller.js in my lightning component.

My goal is to bundle up all my javascript functions and classes and use across most components, and NOT paste them in the helper.js everytime!

in static resource (BaseFunctions / public / application/javascript)

window.BaseFunctions = (function() {
    var _toast = function (type, title, message, data) {
        let params = {
            'mode': 'dismissible',
            'duration': '5000'
        };
        if (type === 'info' || !type) {
            params.title = title || 'Info';
            params.key = 'info_alt'; // or info
            params.type = 'info';
        } else if (type === 'success') {
            params.title = title || 'Success';
            params.key = params.type = 'success';
        } else if (type === 'warning') {
            params.title = title || 'Warning';
            params.key = params.type = 'warning';
        } else if (type === 'error') {
            params.title = title || 'Error';
            params.key = params.type = 'error';
        }
        if (Array.isArray(data)) {
            params.messageTemplate = message;
            params.messageTemplateData = data;
        } else {
            params.message = message;
        }
        $A.get('e.force:showToast').setParams(params).fire();
    };
    var _refreshView = function () {
        $A.get('e.force:refreshView').fire();
    };
    var _closeQuickAction = function () {
        $A.get('e.force:closeQuickAction').fire();
    };
    return {
        toast: _toast,
        closeQuickAction: _closeQuickAction,
        refreshView: _refreshView
    };
}());

in .cmp file

<ltng:require scripts="{!$Resource.BaseFunctions}" />

in controller.js / init function

BaseFunctions // this is undefined!
// this obviously also crashes the component
BaseFunctions.toast('info', null, 'test message');

The ugly solution: This is tested and gives result.

added this to .cmp

<aura:attribute name="templateLoaded" type="Boolean" default="false" />
<aura:attribute name="scriptsLoaded" type="Boolean" default="false" />
<!-- already had these 2, for anyone who needs the full code -->
<aura:handler name="init" value="{!this}" action="{!c.doInit}"/>
<ltng:require scripts="{!$Resource.BaseFunctions}" afterScriptsLoaded="{!c.afterScriptsLoaded}"/>

and in the controller.js

doInit: function (component, event, helper) {
    component.set('v.templateLoaded', true);
    $A.enqueueAction(component.get('c.fullLoadCheck'));
},
afterScriptsLoaded: function(component, event, helper) {
    component.set('v.scriptsLoaded', true);
    $A.enqueueAction(component.get('c.fullLoadCheck'));
},
fullLoadCheck: function(component, event, helper) {
    if (component.get('v.templateLoaded') && component.get('v.scriptsLoaded')) {
        $A.enqueueAction(component.get('c.realInit'));
    }
},

// real init. template and the static js-libs loaded.
realInit: function(component, event, helper) {
    console.log('realInit');
    BaseFunctions.toast('success', null, 'it worked');
},
  • So I had to use a hacky way to finally get the real init here. Thanks to @DavidReed – Mac A. Aug 10 '18 at 20:49
4

Your scripts from <ltng:require> are not guaranteed to be available in your component's init handler. They are loaded asynchronously. You need to add the attribute

 afterScriptsLoaded="{!c.afterScriptsLoaded}"

to your <ltng:require> tag, and implement a afterScriptsLoaded handler function in your component controller to take any actions that are required when your script library becomes available to the component.

See Using External JavaScript Libraries :

The afterScriptsLoaded action in the client-side controller is called after the scripts are loaded and the component is rendered. Don't use the init event to access scripts loaded by <ltng:require>. These scripts load asynchronously and are most likely not available when the init event handler is called.

  • I console.log ed everything, and scripts are loaded before init! – Mac A. Aug 10 '18 at 20:08
  • Yes, but you cannot guarantee that. You're baking in a race condition. There may also be some Locker Service intermediation that I'm not enough of a Lightning guru to dig into. – David Reed Aug 10 '18 at 20:09
  • You're right! 1 out of 3 times it loaded it after – Mac A. Aug 10 '18 at 20:21
  • so no way to have a functions bank! like how jquery works, defined and used everywhere – Mac A. Aug 10 '18 at 20:26
  • @MacA. Yes, it's a security feature, actually. – sfdcfox Aug 10 '18 at 20:53

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.