2
votes

Reading up on the documentation for Ember, I was under the impression that when an action is triggered by a component, it will go up the hierarchy until it hits an action with that name. But here's what's happening right now. I have a game-card component written like so:

game-card.hbs

<div class="flipper">
  <div class="front"></div>
  <div class="back">
    <img {{action "proveImAlive"}} src={{symbol}} />
  </div>
</div>

game-card.js

import Ember from 'ember';

    export default Ember.Component.extend({
      classNames: ['flip-container'],
      actions: {
        //blank for now because testing for bubbling up
      }
    });

Now according to what I've read, since game-card.js does not have a 'proveImAlive' action, it will try to bubble up the hierarchy i.e. the controller for the particular route.

play.js (the route /play)

import Ember from 'ember';

    export default Ember.Controller.extend({

      actions: {
        proveImAlive() {
          console.log('Im aliiiiveeee');
        }
      }
    });

But when I finally run my application, I get this error:

Uncaught Error: Assertion Failed: <testground@component:game-card::ember483> had no action handler for: proveImAlive

Now my question is twofold:

  1. Why is this error happening?

  2. I want some of my component's actions to bubble up to the route's controller. For example, when a game-card is clicked, i'd like to send the id value (to be implemented) of that card up to the controller so it can store it on an array.

    game-card is clicked --> sends value of 1 --> arrayinController.push(1)

How can I achieve this?

3

3 Answers

4
votes

First, I'd like to point out that you linked to the documentation of Ember v1.10.0. You should consult the documentation for the version of Ember you are utilizing, which you mention is v2.8.0.

Now according to what I've read, since game-card.js does not have a 'proveImAlive' action, it will try to bubble up the hierarchy i.e. the controller for the particular route.

This isn't quite what happens because components are isolated, so there is no implicit bubbling. When the Guides say "actions sent from components first go to the template's controller" and "it will bubble to the template's route, and then up the route hierarchy" they mean that you have to explicitly send an action up from the Component. If the component is nested inside another component, you have to do this for each layer, until you reach the Controller.

  1. Why is this error happening?

You need to bind the action in the template: {{game-card proveImAlive="proveImAlive"}}

  1. i'd like to send the id value (to be implemented) of that card up to the controller so it can store it on an array.

I am going to be using closure actions for this part of the answer. As mentioned by @kumkanillam, they have better ergonomics, and they are the current proposed way to use actions if you consult the Guides.

I have prepared a Twiddle for you.

a) Initialize array in the controller

export default Ember.Controller.extend({
  appName: 'Ember Twiddle',
  gameCards: null,

  init() {
    this.set('gameCards', []);
  }
}

b) Implement the action that pushed to the array

export default Ember.Controller.extend({
  appName: 'Ember Twiddle',
  gameCards: null,

  init() {
    this.set('gameCards', []);
  },

  actions: {
    proveImAlive(cardNo) {
      this.get('gameCards').pushObject(cardNo);
      console.log('Im aliiiiveeee - cardNo', cardNo);
    }
  }
});

c) Bind the closure action down

{{game-card proveImAlive=(action 'proveImAlive')}}

d) Trigger the action passing the arguments

<div class="flipper">
  <div class="front"></div>
  <div class="back">
    <button {{action proveImAlive 1}}> ProveIamAlive</button>
  </div>
</div>
2
votes

You need to explicitly set the action handler:

{{component-name fooAction=fooHandler}}

This is required because it helps keep components modular and reusable. Implicit links could result in a component triggering unintended behavior.

0
votes

Your code should work, only if you have included game-card component into play.hbs. I doubt the controller for the particular route is not play in your case.

Here is the working-twiddle

Instead of bubbling actions, use closure actions. For better understanding you can go through the below links,
https://dockyard.com/blog/2015/10/29/ember-best-practice-stop-bubbling-and-use-closure-actions
http://miguelcamba.com/blog/2016/01/24/ember-closure-actions-in-depth/
https://emberigniter.com/send-action-does-not-fire/