Skip to content

Conversation

@ngokevin
Copy link
Member

@ngokevin ngokevin commented Jun 5, 2017

Description:

(reopened to update GitHub after last outage)

Consider <a-entity foo bar="a: 10"> where foo does setAttribute('bar', {b: 20}). The resulting data should be {a: 10, b: 20}, but the data ends up {b: 20} because the setAttribute takes over the initialization process and the DOM data gets ignored.

Ran into this when I had raycaster set a line component with start and end. I was trying to set the color and width via HTML, but that data was wiped out. <a-entity raycaster="showLine: true" line="color: red; width: 0.05">.

This would have also helped cases where we were setting dependencies to satisfy this lifecycle. But that would initialize the component in cases we might not want to (e.g., raycaster might not always want a line). Before we had obj-model set a dependency on material to use its data if defined. We ended up having to remove that.

Changes proposed:

  • In setAttribute, check if the component is defined in the DOM and has not yet been initialized. If so, then initialize it immediately using DOM data before applying new data.
@dmarcos
Copy link
Member

dmarcos commented Jun 5, 2017

I see the level of a asynchronous a potential problem in the future. Is there any way to make it synchronous? is not calling updateComponent enough?

if (isDebugMode) { this.components[attrName].flushToDOM(); }
// Wait for compoent to be initialized with DOM data.
if (!this.components[attrName] && this.hasAttribute(attrName)) {
this.addEventListener('componentinitialized', function waitForInit (evt) {
Copy link
Member

@dmarcos dmarcos Jun 5, 2017

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can we do?

this.updateComponent(attrName);
this.setAttribute(attrName, arg1);
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This would force the initialization of the pending component and then we can set it.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

That sort of makes the lifecycle unpredictable. I'd be more comfortable letting things initialize from the normal attachedCallback flow (attachedCallback -> load -> updateComponents), and then try to set. Clear order of init everything first, then run updates.

Forcing an update would change the order of things, and thinking about stuff like dependencies.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Might work. I can try. dependencies doesn't matter since initComponent will set them up. In the case another component depends on it, it's fine to init it a little early.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

OK, updated.

return;
}

// Initialize component first if not yet initialized.
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

All the real changes are in this clause. The rest was collapsing the indent with an early return.

@dmarcos dmarcos merged commit 70eea24 into aframevr:master Jun 6, 2017
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

2 participants