Search code examples
ember.jscomponentsobservers

How do I control ember component observer execution order?


I have a component within a component. The child component has two properties passed-in via the template. These properties both have separate observers within the child's component.js.

When I update the bound properties in the parent component in a specific order, the child component's observers fire in the wrong order.

How can I control the order in which the observers fire in the child component?

My specific case.

It's been pointed out to me that observers shouldn't be necessary anymore. But they still exist in ember 2.0 so there must be use for them yet. I'll explain my situation anyhow and hopefully the wiser of you out there can let me know how to accomplish this without observers.

In my case, the parent component is a menu for a game, containing many submenus. To switch between each submenu, I use a slide animation so the current menu disappears off screen and the new menu enters swapping the two animating menus in and out as needed. This is accomplished in a side-switcher component (the child in this case).

The parent menu contains tabs which when clicked, need to communicate to the child side-switcher component which submenu should now be shown, and which direction to slide (the two properties). The direction needs to be set first, then the submenu since when the submenu changes, that's what triggers the actual animation. Ember 2.0 philosophy states actions cannot go down, but data (properties) can, so observing properties is the road I'm going down.

Note, in my use case it's actually only the menu property which gets observed, but while debugging this, I had to observe the direction property as well, since my menus were sliding the wrong way all over the place.


Solution

  • Thanks Artych, it was actually the didUpdateAttrs hook which solved my problem since I need to be able to react on all changes to one of the attributes, separate to initialisation.

    Given a component consumed like so:

    {{my-component myAttr=changeableAttr myOtherAttr=otherAttr}}
    

    In the component.js:

    didUpdateAttrs(options){
    
        if( options.newAttrs.myAttr !== options.oldAttrs.myAttr ){
    
          // React to changes outside the component
    
        }
    
    },
    

    This is fired after all attribute changes in any given run loop, and allows you to process within the component in whatever order you like.

    This has also answered the question of how to send actions to components for me, or to be more accurate, how to get a component to react to outside changes.

    For completeness sake, I did work out how to change the order in which observers are fired too: it was simply the order they are defined on the component in the template. This is pretty bad design to rely on this, so it makes sense there is a much better solution in the form of didUpdateAttrs or didReceiveAttrs.