3

I have a Lightning Community and I'm using a custom HTML template to render my pages, inside this HTML template I have a v.body where my custom components are being displayed (the ones selected from the community builder).

So the weird thing I found out is that even when I code this:

<aura:if isTrue="{!false}">
    {!v.body}
</aura:if>

The init handler of my custom components that go inside the "aura:if" is executed, although the components are not displayed on the DOM.

This is a big problem for me since I'm loading an external library on my HTML Template and rendering the {!v.body} afterScriptsLoaded, but my components keep crashing because my custom components use those libraries and the init handler keeps executing even when the isTrue statement is false. And I don't want to add my scripts on every single component inside my pages.

This seems to be a lightning bug, but I would like to be sure about this.

4

So, the specifications for aura:if explicitly state it needs an expression, however the attribute isTrue itself does say its a boolean.

Given that, I would expect your syntax to work however it looks like it may be treating it is a truthy String.

The easiest fix is to pass in an attribute like this:

<aura:attribute name="myBool" type="Boolean" default="false"/>

<aura:if isTrue="{! v.myBool }">
 ...
</aura:if>
  • the component is not being rendered, that means that my code is working. However, the "init" event is still being executed, that I think is the bug, Lightning is initialising the component even if the condition is false, but I guess this is because is a Page Component inside a Lightning community. – Ismael Slimane Jul 20 '18 at 14:24
2

You could load your scripts into just one component and call it using promises. Then you never need to worry about afterscriptsloaded or bad references.

You'd have a component - say called "ScriptLoader".

ScriptLoader would have these top level attributes:

<aura:attribute name="yourscriptsource" type="String" default="{!$Resource.yourscriptname}"/>
<div>
  <div class="scriptdiv" id="{!GlobalId + '_scriptdiv'}"/>
</div>
<aura:attribute name="scriptsLoaded" type="Boolean" default="false"/>

Plus a public method like this:

getYourScript: function(component) {
  return new Promise($A.getCallback(function(resolve, reject) {

    if (component.get("v.scriptsLoaded") == true) {
      resolve(window.yourscript);
    } 
    else {

      // Create script element and set attributes
      var script = document.createElement('script');
      script.type = 'text/javascript';
      script.async = true;
      //resource reference to your script 
      script.src = component.get("v.yourscriptsource");

      var el = document.getElementsByClassName('scriptdiv')[0];
      el.parentNode.insertBefore(script, el);

      // Resolve the promise once the script is loaded
      script.addEventListener('load', () => {
        component.set("v.scriptsLoaded", true);
        resolve(window.yourscript);
      });

      // Catch any errors while loading the script
      script.addEventListener('error', () => {
        reject('yourscript failed to load');
      });
    }

  }))
},

Assuming you have defined this method as an aura:method on the component, you can then call it like this:

var scriptLoader = component.find('scriptLoader');
scriptLoader.getYourScript()
  .then(
    yourscript => {
      yourscript.something()
    }
  )
  .then(
    (someresult) => {
      //do something else
    }
  )
  • Thanks for your answer! I guess that would work if the caller component is the parent component, but this is not my case, and I would prefer not adding this 'ScriptLoader' component everywhere or having to add any logic inside every component that needs the script. – Ismael Slimane Jul 14 '18 at 11:31
  • Yes, if you were to use the component only for loading scripts, then you mayaswell just use the built in loader. However, I actually use this component for most DML and SOQL calls (when I'm not using a recorddata component), so it becomes quite useful. – Caspar Harmer Jul 14 '18 at 19:14
0

You can always try to replace aura:if with aura:renderIf it is little bit different and does not render any content until variable changes. Salesforce states it is slower, but I had multiple issues with aura:if that were simply resolved by using aura:renderIf

  • 1
    aura:renderIf is deprecated, so you are taking a pretty big risk that this function will entirely disappear. – Caspar Harmer Jul 9 '18 at 7:43
  • I know it is, but aura:if is broken in some cases. – Paul Jul 9 '18 at 8:46
  • 1
    @Paul which cases? I've been using it quite reliably – tsalb Jul 9 '18 at 15:57
  • If you could show us some cases of it not working (maybe in a new linked ticket) we might be able to debug for you... I'm pretty sure aura:if is solid – Caspar Harmer Jul 9 '18 at 18:35

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.