[SalesForce] jQuery NiceScroll not working when Locker Service is active

I am having an issue when using NiceScroll (GIT Hub) when locker service is enabled.

If the locker is turned off, it work's fine.

Code:-

Component:

<ltng:require scripts="{!join(',',
     $Resource.namespace__StaticResourceName + '/scripts/jQuery_V1.js',
     $Resource.namespace__StaticResourceName + '/scripts/nicescroll.js'
     )}" afterScriptsLoaded="{!c.scriptsLoaded}" />

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

<div class="slds-form-element__control textarea-wrapper">
    <ui:inputTextArea value="{!v.newVF.namespace__Notes__c}" aura:id="editModeScrollBarY" maxlength="255" 
    class="slds-textarea scrollbar-outer"/>
</div>

Controller:

scriptsLoaded : function(component, event, helper) {
        component.set("v.isResourcesLoaded", true);
}

Helper:

    addScroll : function(component){
       if(component.isValid() && component.get("v.isResourcesLoaded")){
            $(".scrollbar-outer").niceScroll({
                  boxzoom:false,
                  autohidemode:false,
                  cursorcolor:"#9c9c9c",
                  nativeparentscrolling: true 
            });
       }
    }

Renderer:

({
    afterRender: function(component, helper) {
        this.superAfterRender();                    
    },
    rerender: function(component, helper) {
        this.superRerender();   
        helper.addScroll(component);
    }   
})

isResourcesLoaded is a Boolean attribuite which I'm setting as true in afterScriptsLoaded (to make sure that the external scipts uploaded as static resources have loaded).

Also, I'm calling the addScroll function from the renderer to make sure that the DOM elements have also loaded successfully before adding scroll to a DOM element.

The above code works fine when locker service is not active.

It would be very helpful if anyone can provide a solution to solve this issue.
Also, is there any alternative to add scroll to a textarea with LS active for Salesforce-1?

Best Answer

When locker service is in place, the golden rule is:

you cannot access the DOM of the components you do not own

Why this is enforced?

It is mainly to preserve the component encapsulation, so that developer can not accidentally/intentionally access the other developers component(one's they do not own) or even in worst case break other components functionality and also others security related stuffs are involved too.

Here a blog which details constraints imposed to access DOM, when locker service is in place.

Since the <ui:inputTextArea/> component belongs to the ui namspace, to which do not have access to its DOM.To solve this, you can use the <textarea/> HTML tag instead of the former.

Below is the code which I tried:

Jquery - V2.2.4

Nicescroll - V3.6.8

Component:

<aura:component controller="FullCalendarController" implements="force:appHostable" access="public">
    <ltng:require scripts="/resource/jquery224,/resource/nicescroll" afterScriptsLoaded="{!c.afterScriptsLoaded}" />
    <ltng:require styles="/resource/SLDS202/assets/styles/salesforce-lightning-design-system.css"/>
    <aura:attribute name="isResourcesLoaded" type="Boolean"/>
    <aura:attribute name="test" type="String" default="hello world"/>
    <div class="slds">
        <div class="slds-form-element__control textarea-wrapper">
            <textArea aura:id="editModeScrollBarY" maxlength="255" 
                      class="slds-textarea scrollbar-outer" onblur="{!c.updateNoteValue}">{!v.test}</textArea>
        </div>
    </div>
</aura:component>

Controller.js

({
    afterScriptsLoaded: function(cmp,evt,helper){
        cmp.set("v.isResourcesLoaded",true);
    },
    updateNoteValue : function(cmp,event){
        //manully set the attribute value.
        cmp.set("v.test",event.currentTarget.value);
    }
})

Helper:

addScroll : function(component){
       if(component.get("v.isResourcesLoaded")){
            //Do Not use $(".scrollbar-outer") selector, it will break the component encapsulation.
            //Because jquery will search for the DOM in whole the document rather than your component.

            $(component.find("editModeScrollBarY").getElement()).niceScroll({
                  boxzoom:false,
                  autohidemode:false,
                  cursorcolor:"#9c9c9c",
                  nativeparentscrolling: true 
            });
       }
    }

Renderer:

({
    afterRender: function(component, helper) {
        this.superAfterRender();                    
    },
    rerender: function(component, helper) {
        this.superRerender();   
        helper.addScroll(component);
    }   
})

--Update--

Even though the native scrollbar is replaced with custom scroll but I tried few things to make the content inside the textarea to scroll with locker service turned on but it did not work. :-(

nicescroll in text area

P.S: I observe the same behaviour in SF1 too.

Related Topic