Reputation: 3325
I'm trying to figure out why an Ember component is not working (and trying to learn about component lifecycles in the process). The component in question is Ember-cli-mapbox. It uses nested components. You can have a mapbox-map
component, and within that component you can have several mapbox-marker
components. Now, how it is supposed to work, is the mapbox-map
component initialises the map, and then passes a block to the child marker components. The child marker components then references the map that got passed down to them. An example of the components in use (which come from the component docs):
{{#mapbox-map mapId='ember-cli-mapbox.7c3914f2' as |map|}}
{{#each positions as |position|}}
{{mapbox-marker map=map coordinates=position.coordinates}}
{{/each}}
{{/mapbox-map}}
Now, the components get set up using the didInsertElement
hook, which makes sense to me since the DOM needs to be in place before the mapbox-map
component can bind to a element in the dom. It doesn't work like that though. The didInsertElement
of the child components get executed before the didInsertElement
hook in the parent component. So, the marker tries to reference the map before it was created. I figured this out by putting console.log
s in the component init code. I can't find much documentation on component lifecycles. didInsertElement
does get referenced in the API docs here, but it seems that the newest API docs are actually out of date and don't reference a bunch of other hooks described here. The latter link says that life cycle events happen in the following order:
didInitAttrs
didReceiveAttrs
willRender
didInsertElement
didRender
Now, things get weird. When I replace didInsertElement
in the components with didInitAttrs
, it fires in the correct order. The didInitAttrs
hook on the parent component fires first, followed by the child component didInitAttrs
hooks. Problem with this is, the DOM isn't ready yet, so it doesn't help much. I also can't put the map binding event in the Ember runloop, since it need to be returned and passed as a block to the child elements.
So, my questions are:
didInsertElement
on components, do the hooks get executed in the order they do? (children, then parents)I've recreated the addon in an Ember Twiddle here. Child hooks get called before the parent hooks, causing the component to break since map
is undefined when the hook is called. This happens on Ember 1.13.8 as well as 1.13.9.
Upvotes: 3
Views: 2574
Reputation: 12796
Why, when using didInsertElement on components, do the hooks get executed in the order they do? (children, then parents)
This was changed in version 1.8. It was previously parent, then children but this often required people to use some complicated method of waiting for children to render to do certain things. Changing the order made learning Ember simpler.
See https://github.com/emberjs/ember.js/issues/5631 for more information.
How did this component ever work in the way it's currently written?
I have not used this addon, and have no idea if it works or not. I fixed your twiddle to work, however: http://ember-twiddle.com/4c3e55d0a66ead378bdf
Am I supposed to use the above mentioned hooks if they're not mentioned in the official API docs?
These hooks are not mentioned because the documentation is still catching up to changes in Ember. Feel free to use them if you'd like.
Upvotes: 4