A possible actions down pattern


#1

We all know the infamaus Data Down Actions Up (DDAU) montra and for 95% of the time this is your best tool on your tooll belt. However, there are rare cases when telling a component to do something is the best soolution.

First and for most when you want to expose a component’s actions you will likely use a contetual component which yields an action that any child node/component can tap into. This is your best bet.

<MyCompnent as |actions|>
  <button {{action actions.myAction}}>
    Go
  </button>
</MyComponent>

But in the case of the parent needing to tell the chilld something there are three methods.

  1. Use a mediator service
  2. Send spacialized data down (for example a counteer or specialized bound property
  3. Direct function call via a broker or manager interface

In this post I will focus on option three because the first two are not ideal and do not offer a direct connection between the parent and the child. Option one suffers from an indirect path and is not declarative. It leave a level obfucation in the mix and usually deals with globals or event driven designs.

Option two is even worse as it takes the call stack out of the equasion and you are left not realizing who or what or how things came to be. Not to mentin this is essentually the very definition of using an observer. And it is common understanding that events and observers lead to trouble.

Option three is direct, uses function calls so you can pass in data and get the return results. Offers a call stack. And is declaritive. And because it offeres a encapsulated interface the pattern is decoupled which means it is not dependedn ton the parent like the other options are.

The pattern is basically a didInsertElement hook that calles an action passing it a bound Manager object that has function on it that know how to interface with the component. Say for example you have a component with a form and it knws how to submit the form. It includes a submit button; then the desiners want the same form to also be used in a modal and they want the act of closing the modal to autosubmit the form.

In the form component we will offer a Manaer via our didInsertElement hook.

didInsertElement() {
  this._super(...aguments);
  this.registerFormManager({
    submit: () => this.submit(),
    reset: () => this.reset()
  });
}

Now the parant can call the form component like so—

<MyForm @registerFormManager={{action (mut this.formManager)}}/>

And now our prent has direct accces to call functions on the manager.

this.formManager.submit();
this.formManager.reset();

With this pattern we have provided an escape hatch to allow a parent component to send a message to a child without resorting to indirect and awkward mechinisms that we know does not scale well. Instead we offer a clear interface that the child has controll over. This follows the S.O.L.I.D. principles of OOP.

I hope this idea can help someone write cleaner code.


Version 2.x : How to force a rerender on a component?