5

I have a lightning component setup where in a parent component I dynamically create a component and assign it to an <aura:attribute type="Aura.Component" />. The dynamically created child component has an <aura:method /> on it. The controller action for that method does some DOM manipulation on a node inside the dynamically created component (this should be totally valid in Locker Service since we are accessing a DOM node inside the same component). However, getElement() is not available when the component was dynamically created. If I instead directly place the component inside the parent component with <c:myCmp /> when I call the same function getElement() is available.

Is there something special I need to do in order to make sure dynamically created components have getElement() available within their own controller code or is this simply a bug in Locker Service?

UPDATE - GIST

Here is a gist that will showcase the issue: https://gist.github.com/dsharrison/bf2ceaf22820bbfb79cef042fd2e5d8d

With Locker Service disabled, both buttons will report that getElement() is available. Once enabled, the dynamic button will lose access to getElement().

  • would love to see reduced gist to further investigate ? Also does it work with locker disabled to call it as a locker issue ? – Mohith Shrivastava Nov 30 '16 at 3:14
  • 1
    I'll put the gist together and yes, disabling locker service restores the intended functionality. – dsharrison Nov 30 '16 at 3:19
  • 1
    @MohithShrivastava just added a gist. I stripped a lot of stuff out from our actual use case to just highlight the issue we are seeing but let me know if you have any questions about why things are set up the way they are or if you need more info. – dsharrison Nov 30 '16 at 3:35
2

The gist is excellent - thank you!

I would actually expect both scenarios to "fail" because Component.find() and $A.createComponent() should both yield a SecureComponentRef and not a SecureComponent. Component.find()'s behavior is the expected/working as designed one and we will closing the createComponent() hole soon.

A component is meant to be an encapsulated unit and the supported public API it exposes consists of its attributes, methods, and events - not its internal DOM structure. Lightning Components are secure/encapsulated by default. The internals of c:LSTestChild are its private parts in unless it explicitly chooses to expose them.

  • I thought though that because I am invoking a public method on c:LSTestChild from my parent component that the context then switches to c:LSTestChild when it is executing the controller function associated with that method. Correct me if I am wrong but I don't believe I am trying to access the DOM from the parent (which is not allowed in Locker Service for good reason) but am instead invoking a public method on the child to tell it to modify its own DOM element (which should be totally fine). – dsharrison Nov 30 '16 at 16:18
  • Filed W-3536905 to track this issue. Please reference this bug when you create a support case. – Ravi Jayaramappa Nov 30 '16 at 18:53
  • @RaviJayaramappa thanks for filing the ticket. I don't have premier support so I won't be opening a case. Does the ticket refer to the behavior from my above comment (and do you agree that what I am trying to do is totally valid in Locker Service)? – dsharrison Nov 30 '16 at 20:29
  • @D.S. There definitely is a bug here either way because behavior should be consistent if you create the component dynamically or grab it from markup. To clarify the gist, are LSTestButton.cmp and LSTestChild.cmp in the same namespace? – TrevorBliss Dec 1 '16 at 0:36
  • @TrevorBliss yes, these components are in the same namespace. – dsharrison Dec 1 '16 at 0:44
0

Okay, so I finally figured out where we were going wrong with help from the comments from @TrevorBliss. The difference between our actual code and the gist is that we were using window.setTimeout to perform the DOM manipulation in the init event to animate some elements so that they would transition from an initial state to a a new state. In that context component.isRendered() is false because the DOM has not finished updating. This did not pose any actual functional problem for us since by the time the timeout started its updates the DOM was always ready. However, moving this logic to the afterRender allows the DOM updates to be complete so that component.isRendered() is true and we can use component.getElement() to access the actual node.

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.