Nate Thompson
Nate Thompson

Reputation: 405

Ember: Send child component's action to a parent component

I am trying to call/trigger a child component's action from a parent. I've tried this a couple ways but I'm not getting anywhere. This is basically what I have so far.
I am attempting to send the action up to the parent by passing it as a parameter in the action that was passed down...
This seems a bit like a spaghetti situation but the way my project is organized, this is my result.

If anyone could, please tell me how to successfully pass an action up to the parent as a parameter. (I'm curious to know how, if possible)
If anyone also has a better suggestion on how to call a child's action, please share. Thanks in advance!

parent-component.hbs

{{child-component anAction=(action "anAction")}}
<div onclick={{action actionPassedFromChild}}></div>

parent-component.js

actionPassedFromChild: null,
....
actions: {
    parentAction(childAction){
       this.set('actionPassedFromChild', childAction);
    }
}


child-component.hbs

<div onclick={{action "anAction"}}

child-component.js

....
actions: {
    anAction(){
       this.parentAction(childAction);
    }
    childAction(){
       //Some operation
    }
}

In this example, if I stop the code inside of 'anAction', I do have 'childAction'. But by the time that it gets passed into 'parentAction', it is undefined. Could anyone explain why?

Upvotes: 1

Views: 2143

Answers (1)

Gennady Dogaev
Gennady Dogaev

Reputation: 5991

It seems like you have some typos. For example, parentAction is not passed to child component. But if I understood what do you want to achieve right - it is doable, however I can't even imagine why you might need this.

You can play with my example here. Select is in child component and button is in parent component. When you choose something in select - child component sends one of two functions to parent component. And when you click a button - parent component calls that function.

Code:

//child-component.js
import Ember from 'ember';


export default Ember.Component.extend({
  line1: "Say Hi!",
  line2: "Say Yeah!",

  changeAction(newAction) {
    switch (newAction) {
      case "1":
        this.onActionChange(this.action1);
        break;

      case "2":
        this.onActionChange(this.action2);
        break;

      default:
        this.onActionChange(undefined);
        break;
    }
  },

  action1: Ember.computed(function(){
    const that = this;
    return function() {
      alert(that.line1);
    }
  }),

  action2: Ember.computed(function(){
    const that = this;
    return function() {
      alert(that.line2);
    }
  })
});

//child-component.hbs
<select  onchange={{action changeAction value="target.value"}}>
        <option>Choose something</option>
        <option value="1">Action 1</option>
    <option value="2">Action 2</option>
</select>

//parent-component.js
import Ember from 'ember';

export default Ember.Component.extend({
  childishAction() {
    if (typeof this.childAction === 'function') {
      this.childAction();
    }
  }
});

//parent-component.hbs
{{child-component onActionChange=(action (mut childAction))}}
<div><button disabled={{unless childAction true false}} onclick={{action childishAction}}>Let's do it!</button></div>

What happens here - you can't pass to action helper something that is not defined when ember renders template. So you need to store action that child-component sends into some variable and call it using some intermediate action of parent component.

In my example, function returned from child component is stored in childAction property of parent component and childishAction of parent component calls it.

Hope this helps. But you probably trying to solve some problem in not a right way.

Upvotes: 2

Related Questions