4

I am facing an issue with the Locker Service. I have a simple piece of code. I have attached the code here. The issue is that if the Locker Service is disabled, I am able to open a link in new tab using "target" attribute the element output is as shown in the screenshot. Whereas, if it is enabled, I am unable to open a link in new tab using "target" attribute. I have attached both screenshots as well as the code. Winter 17 - Salesforce

DemoTestApp.app

<aura:application >
 <c:testJqueryComponent />
</aura:application>

DemoTest.cmp

<aura:component >
<ltng:require scripts="{!join(',',
                       $Resource.jQuery + '/jquery/lightning/js/jquery-2.2.4.min.js',
                       $Resource.jQuery + '/jquery/lightning/js/jquery-migrate-1.3.0.min.js')}" 
              afterScriptsLoaded='{!c.doResult}'/>
<div id="divTest"></div>
<button id="btnView" >Read TR</button>
</aura:component>

DemoTestController.js

({
    doResult : function(component, event, helper) {
    $("#divTest").html('<table><tr role="row">'
                       +'<td role="cell" aria-describedby="1">value 1</td>'
                       +'<td role="cell" aria-describedby="2"><a target="_blank" href="www.google.com">google</a></td>'
                       +'</tr></table>');
}
)}

Elements output: Locker service is disabled enter image description here

Elements output: Locker service is enabled enter image description here

4
  • This isn't expected behavior. Please open a case with this repro so we can track the investigation/fix. Nov 28, 2016 at 17:32
  • 1
    When you open a case, please W-3530603 as the bug number for this issue. Nov 28, 2016 at 18:22
  • If you're curious about the technical details, this is happening because jQuery's html() API sets the string you pass it to .innerHtml and Locker will sanitize anything passed to .innerHtml with a library called DOMPurify. DOMPurify automatically strips the target attribute from anchor tags. Nov 29, 2016 at 4:39
  • @RaviJayaram we opened the case and case no 15210750. Nov 29, 2016 at 6:00

4 Answers 4

3

The fix for this is scheduled to be released in the Spring '17 major release.

Until then please try to move your HTML in to your markup file. Or you can try a dynamically created component solution like @Pavlonator suggests, though that is a bit of extra overhead.

1

What lightning does - it sanitized everysingle DOM element, even document itself, even window. so if you will try to do something ltng consider dangerous - it will block you.

But your case is luckily not dangerous. Even using jQuery should have worked, but untill the locker service bug is fixed, all you have to do is to follow Lightning best practices.Among those there two approaces:

  1. using facets
  2. less encouraged, but still, lightning way - conditional rendering/or css analogue

here is the example with facets:

<aura:attribute name="testBody" access="public" type="Aura.Component[]"/>
<aura:handler name="init" value="{!this}" action="{!c.doInit}" />
<div id="divTest">
    {!v.testBody}
</div>
<button id="btnView" >Read TR</button>

on script load can still be used, it just happened that my example does not need jQuery. extract conditional piece of UI into separate component:

<aura:component >
<table>
    <tr role="row">
        <td role="cell" aria-describedby="1">value 1</td>
        <td role="cell" aria-describedby="2"><a target="_blank" href="www.google.com">google</a></td>
    </tr>
</table>

the controller for your top component (not for the extracted one):

    ({
    doInit: function(cmp, event, helper) {
        $A.createComponent("c:testerTr", {}, function(newCmp, status, errorMessage){
                if (status === "SUCCESS") {
                    var testBody = cmp.get("v.testBody");
                    testBody.push(newCmp);
                    cmp.set("v.testBody", testBody);
                }
                else if (status === "INCOMPLETE") {
                    console.log("No response from server or client is offline.")
                }
                else if (status === "ERROR") {
                    console.log("Error: " + errorMessage);
                }
            });
    }
    })

the example above does render link with blank target with Locker Service enabled.

for the conditional rendering you can use aura:if

if you want to render always but conditionaly show/hide - u can use css classes with -true/-false naming convention and evaluate the class name in lightning expression.

0

By opening in a new window, you're violating a fundamental principle of components. Components aren't supposed to have access the Browser Window in the DOM. In order to open a link in a new window, that's the only way you could possibly do that which I'm aware of. I'll add that Salesforce strongly discourages the use of jQuery libraries in Lightning components which could also be part of your issue; particularly that you've not used <lightning:require? on them.

For more on this see https://developer.salesforce.com/docs/atlas.en-us.lightning.meta/lightning/js_dom_access.htm

5
  • 3
    >Salesforce strongly discourages the use of jQuery libraries - I would not say so. locker service is tested against many if not all versions of jQuery.
    – Pavlonator
    Nov 28, 2016 at 18:07
  • 1
    @Pavlonator. Yes, it's true that it gets tested. If there's a new version that comes out, guess what's likely to break should you try to implement it? As an MVP, in my discussions with SF engineers, they recommend sticking with straight JS and avoiding using jQuery or other 3rd party libraries where possible.
    – crmprogdev
    Nov 28, 2016 at 18:16
  • 1
    Although LockerService restricts unfethered access to the raw window object, most of the APIs have been securely wrapped behind the scenes and exposed. With Locker, you also should be able to create and use DOM elements as you normally would. The biggest restriction there being that you can't read/modify the parts of the DOM you haven't created yourself. In this case, the OP isn't fiddling with parts of the DOM he doesn't have access to and is correct in believing the anchor tag should render with the target attribute. Locker is not explicitly filtering this out. Nov 28, 2016 at 18:25
  • 4
    Re: jQuery libraries.. Salesforce discourages use of 3rd party libraries where they are not completely necessary, since they may introduce incompatibilities with Locker. That being said, any 3rd party library that follows the rules of Locker is totally fine to use. The most common rules broken by these libs are non-compliant CSP (unsafe-inline/unsafe-eval) and strict mode. Nov 28, 2016 at 18:32
  • 4
    @crmprogdev components can have access to window object. To give you and example, component can read window.location.href, but can not call window.location.assign(). Components can read scroll position, which is useful piece of information, but can not scroll forth and back. Components are like good neighbours, they know the news, but never will infringe your property
    – Pavlonator
    Nov 28, 2016 at 19:09
0

Just to add, this is working in IE11. Waiting for the Spring 17 to hit my sandbox next month-Jan 2017 for the Chrome fix.

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.