# Call an action on a component from a controller

**URL:** https://discuss.emberjs.com/t/call-an-action-on-a-component-from-a-controller/9320
**Category:** Ember CLI
**Created:** [December 15, 2015, 8:18pm UTC](https://discuss.emberjs.com/t/call-an-action-on-a-component-from-a-controller/9320 "2015-12-15T20:18:03Z")
**Posts on this page:** 11
**Page:** 1

<div class="post-metadata">

### Author: ![JordanRDesigns](https://sea1.discourse-cdn.com/flex019/user_avatar/discuss.emberjs.com/jordanrdesigns/32/10971_2.png) [@JordanRDesigns](https://discuss.emberjs.com/u/JordanRDesigns)
#### Post date: [December 15, 2015, 8:18pm UTC](https://discuss.emberjs.com/t/call-an-action-on-a-component-from-a-controller/9320/1 "2015-12-15T20:18:03Z")

</div>

Not sure if this is possible or the best way to do this, but I have a component that takes and input and upon sliding a button over it will fire an action that using `sendAction()` to bubble that up where the `item` controller that has the component rendered in it’s template will catch it and call an ajax function.

What I want is when that ajax function resolves with a success, for the button that the user slid over to animate back so they can enter a new input and do it again if they wanted to. I know I can put this animation logic in the success callback of the ajax function but I was wondering if there was a way to keep all that animation logic in the component and out of the controller and just have the controller “defer” the animating to the component by telling the component to animate the button back to where it started.

---

<div class="post-metadata">

### Author: ![palmergs](https://sea1.discourse-cdn.com/flex019/user_avatar/discuss.emberjs.com/palmergs/32/9713_2.png) [@palmergs](https://discuss.emberjs.com/u/palmergs)
#### Post date: [December 18, 2015, 3:38pm UTC](https://discuss.emberjs.com/t/call-an-action-on-a-component-from-a-controller/9320/2 "2015-12-18T15:38:46Z")

</div>

There’s no law that says a component can’t make an Ajax call though I’ve seen posts that seem to frown on it.

If you keep the ajax call in the controller. You could have the controller set an animateState property on the component and then observe it. Perhaps something like:

_app/templates/parent.hbs_

```
{{my-button animateState='ready'}}

```

_app/components/my-button_

```
animateState: 'ready',
oldState: 'ready',
observer: Ember.observer('animateState', function() {
  const currState = this.get('animateState');
  const oldState = this.get('oldState');
  if(currState !== oldState) {
    if(currState == 'ready') { animateReady(); }
    else { animateError(); }
    this.set('oldState', currState);
  }
})

```

---

<div class="post-metadata">

### Author: ![workmanw](https://sea1.discourse-cdn.com/flex019/user_avatar/discuss.emberjs.com/workmanw/32/14929_2.png) [@workmanw](https://discuss.emberjs.com/u/workmanw)
#### Post date: [December 18, 2015, 4:20pm UTC](https://discuss.emberjs.com/t/call-an-action-on-a-component-from-a-controller/9320/3 "2015-12-18T16:20:15Z")

</div>

FWIW, we make AJAX calls from components all the time. In fact, we practice the routable components pattern, so we don’t even have controllers.

But either way, trying to bundle several pieces of state, send it through an action (or chained actions) just to arrive in the controller/route so he can make an AJAX call makes absolutely no sense to me. If the data resides in a service, I could see putting a common function there that makes the AJAX call. Take it from me, when your app gets more complicated, all the “unecessary” action sending makes things more messy than component ajax calls ever will.

---

<div class="post-metadata">

### Author: ![jasonmit](https://sea1.discourse-cdn.com/flex019/user_avatar/discuss.emberjs.com/jasonmit/32/182_2.png) [@jasonmit](https://discuss.emberjs.com/u/jasonmit)
#### Post date: [December 19, 2015, 10:26am UTC](https://discuss.emberjs.com/t/call-an-action-on-a-component-from-a-controller/9320/4 "2015-12-19T10:26:18Z")

</div>

This is what closure actions solves. Actions upstream can return something, in your case a Promise, that the component’s sendAction method will return.

```auto
export default Ember.Controller.extend({
  actions: {
    bar() {
      // your ajax method here..
      return new Ember.RSVP.Promise((resolve) => {
         setTimeout(resolve, 1000);
      });
    }
  }
});

```

```auto
{{x-foo action=(action 'bar')}}

```

```auto
// x-foo
export default Ember.Component.extend({
  sliderDisabled: false,
  actions: {
    triggerFoo() {
      this.set('sliderDisabled', true);
      
      // sendAction here returns the Promise from the action bar
      // the Ember.RSVP.cast is just here to handle the case where
      // a bound closure action doesn't return a promise.. or anything
      Ember.RSVP.cast(this.attrs.action()).finally(() => {
         this.set('sliderDisabled', false);
      });
    }
  }
});

```

---

<div class="post-metadata">

### Author: ![kicauipul](https://sea1.discourse-cdn.com/flex019/user_avatar/discuss.emberjs.com/kicauipul/32/11383_2.png) [@kicauipul](https://discuss.emberjs.com/u/kicauipul)
#### Post date: [December 23, 2015, 1:59am UTC](https://discuss.emberjs.com/t/call-an-action-on-a-component-from-a-controller/9320/5 "2015-12-23T01:59:22Z")

</div>

set a property, for example `loading`, in your controller which have boolean value, set it default to false. Then pass that attribute to the component, on the component make it watch to that property via observer. When action ajax fire, toggle that property on your controller, and when ajax call success, toggle it again. That way you can animate that button on your component.

That my though.

---

<div class="post-metadata">

### Author: ![JordanRDesigns](https://sea1.discourse-cdn.com/flex019/user_avatar/discuss.emberjs.com/jordanrdesigns/32/10971_2.png) [@JordanRDesigns](https://discuss.emberjs.com/u/JordanRDesigns)
#### Post date: [December 28, 2015, 4:58pm UTC](https://discuss.emberjs.com/t/call-an-action-on-a-component-from-a-controller/9320/6 "2015-12-28T16:58:04Z")

</div>

In the console I’m getting

```
Uncaught TypeError: Failed to construct 'Promise': Please use the 'new' operator, this object constructor cannot be called as a function.

```

Is there a way I can call a local component action that is different with each use of the component?

For instance I have the component in an `item` route that I want to call an action called `placeBid`, but I also have this component in a `cart` route that I want to call an action called `placePayment`

When I have one action I know I can just call the action by name and the local action name in the component file will be called, but how can I put both of those actions in the component file and just call those actions based on whcih one I want to call? Is there a certain way I can do it so that the definition of the component (in handlebars) defines the name of the action and that actions gets called locally versus bubbling up to the route/controller?

---

<div class="post-metadata">

### Author: ![jasonmit](https://sea1.discourse-cdn.com/flex019/user_avatar/discuss.emberjs.com/jasonmit/32/182_2.png) [@jasonmit](https://discuss.emberjs.com/u/jasonmit)
#### Post date: [December 28, 2015, 7:19pm UTC](https://discuss.emberjs.com/t/call-an-action-on-a-component-from-a-controller/9320/7 "2015-12-28T19:19:44Z")

</div>

`new Ember.RSVP.Promise`

---

<div class="post-metadata">

### Author: ![jasonmit](https://sea1.discourse-cdn.com/flex019/user_avatar/discuss.emberjs.com/jasonmit/32/182_2.png) [@jasonmit](https://discuss.emberjs.com/u/jasonmit)
#### Post date: [December 30, 2015, 12:14am UTC](https://discuss.emberjs.com/t/call-an-action-on-a-component-from-a-controller/9320/8 "2015-12-30T00:14:46Z")

</div>

> [@JordanRDesigns](#):
>
> Is there a way I can call a local component action that is different with each use of the component?

I would opt for inheritance in this case and in the case `{{x-foo-cart}}` `{{x-foo-item}}`. Without knowing much detail on what you’re building, it sounds like the the “local” action should be an outside concern.

cart route/controller: `{{x-foo action=(action 'cartAction')}}`

item route/controller: `{{x-foo action=(action 'itemAction')}}`

This pattern usually allows for a more reusable component versus a monolithic component with business logic to handle many implementations.

---

<div class="post-metadata">

### Author: ![JordanRDesigns](https://sea1.discourse-cdn.com/flex019/user_avatar/discuss.emberjs.com/jordanrdesigns/32/10971_2.png) [@JordanRDesigns](https://discuss.emberjs.com/u/JordanRDesigns)
#### Post date: [January 4, 2016, 6:43pm UTC](https://discuss.emberjs.com/t/call-an-action-on-a-component-from-a-controller/9320/9 "2016-01-04T18:43:46Z")

</div>

So, I’ve implemented the code you outlined here with `Ember.RSVP.Promise` and it appears to be working however it’s not actually waiting for the `resolve` before if calls the code in the `.finally()` block.

```auto
callAjaxAction() {
      this.setProperties({working:true});
      Ember.RSVP.cast(this.sendAction()).finally(() => {
        Ember.$('.draggable').animate({
          left: this.get('startingPosition')
        });
        this.setProperties({working:false});
      });
    }

```

In my controller I have this action

```auto
placeDonation() {
  		return new Ember.RSVP.Promise((resolve) => {
         setTimeout(()=>{
      		this.get('notification').notify({message: "Your donation has been placed, thanks!",success: true});
         	resolve;
         }, 5000);
      });
    }

```

But when the button is pressed, the `working` property doesn’t get set (meaning it would be set back so quickly ember doesn’t even attempt to change it) and the UI goes back to normal, then 5 seconds later the notification message pops up, which is when the UI should reset, not before like it’s currently doing.

---

<div class="post-metadata">

### Author: ![jasonmit](https://sea1.discourse-cdn.com/flex019/user_avatar/discuss.emberjs.com/jasonmit/32/182_2.png) [@jasonmit](https://discuss.emberjs.com/u/jasonmit)
#### Post date: [January 5, 2016, 3:52am UTC](https://discuss.emberjs.com/t/call-an-action-on-a-component-from-a-controller/9320/10 "2016-01-05T03:52:48Z")

</div>

`this.attrs.action()` instead of `this.sendAction()` also invoke `resolve` in your placeDonations method, you just have `resolve` instead of `resolve()`

---

<div class="post-metadata">

### Author: ![GregWang](https://sea1.discourse-cdn.com/flex019/user_avatar/discuss.emberjs.com/gregwang/32/13186_2.png) [@GregWang](https://discuss.emberjs.com/u/GregWang)
#### Post date: [August 7, 2017, 7:06am UTC](https://discuss.emberjs.com/t/call-an-action-on-a-component-from-a-controller/9320/11 "2017-08-07T07:06:48Z")

</div>

what’s difference between this.attrs.action( ) and this.get(‘action’)( );
