I have two component and one sitting on another. I need to send an event to main route from child component( both components use in same route)
Please let me know is there any standard way to do that.
For short answer you can you can use ember-route-action-helper addon.
<button {{action (route-action 'onButtonClick')}}>ClickToCallRouteAction</button>
There are three way of actions communication,
1. Old style classic functions style ie., passing function name as string from top to bottom. and in all the places we need to define same function and provide. Use sendAction
to bubble. and send
method bubble from controller to route hierarchy.
This is not encouraged. Sample classic style actions twiddle
2. Closure actions
Use action
helper pass function instead of just string. so that you don't need to define it everywhere.
sample twiddle for closure actions style
3. route-action-helper addon
You can directly call route action from anywhere literally by just wrapping functions using route-action
helper.
Sample twiddle
Comparision between Classic style and Closure style and Why Closure is preferrable ?
onclick=(action (mut title) value="titlevalue")
(action 'save' target=session)
would look at the actions
hash on the session
object instead of the current context.Some of the promising article regarding this,
- miguelcamba article ember-closure-actions-in-depth
- emberigniter article send-closure-actions-up-data-owner
- emberjs blog 1.13 release article
- dockyard - ember-best-practice-stop-bubbling-and-use-closure-actions
- blog from Ember map Why action helper?
- blog from Alisdair McDiarmid ember-closure-actions-have-return-values
- blog from alexdiliberto ember-closure-actions
Starting with Ember 3.14, Octane, we can solve this problem in a modern, explicit, concise and clear way -- which we'll get to after this brief intermission:
I need to send an event to main route from child component
While this is possible, it's strongly recommended against, as Routes should not have actions and should be stateless. That said, we can solve the problem of action passing through deep components in a couple of ways:
For the first, Data Down, Actions Up, you may pass arguments down as many component layers as you desire
// app/controllers/application.js:
@action
dance(){
console.log('┏(-_-)┓┏(-_-)┛┗(-_- )┓')
}
// app/templates/application.hbs
<Foo @dance={{this.dance}} />
// app/components/foo.hbs
<Bar @dance={{@dance}} />
// app/components/bar.hbs
<button {{on 'click' @dance}}>Dance!</button>
This could be a slipperly slope. While only having two components to data down, and to action back up (after a click in this case), it may not seem like too much effort, but many UIs could be 10+ components deep, and would lend themselves to an anti-pattern known as Prop-Drilling.
To mitigate prop-drilling, we have another approach in our toolbox to reach for. Services!
// app/services/my-service.js
@action
dance(){
console.log('┏(-_-)┓┏(-_-)┛┗(-_- )┓')
}
// app/components/bar.js
import Component from '@glimmer/component';
import { inject as service } from '@ember/service';
export default class Bar extends Component {
@service myService;
}
// app/components/bar.hbs
<button {{on 'click' this.myService.dance}}>Dance!</button>
The deeply nested component can access the action directly, rather than needing to be passed through a few layers -- this leads to much more maintainable and clear code.
Resources
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With