#

API Docs for: v2.11.1
Show: Inherited Protected Private Deprecated

# File: packages/ember-runtime/lib/mixins/action_handler.js

    /**
    @module ember
    @submodule ember-runtime
    */

    import {
      assert,
      deprecate,
      Mixin,
      get
    } from 'ember-metal';

    /**
      `Ember.ActionHandler` is available on some familiar classes including
      `Ember.Route`, `Ember.Component`, and `Ember.Controller`.
      (Internally the mixin is used by `Ember.CoreView`, `Ember.ControllerMixin`,
      and `Ember.Route` and available to the above classes through
      inheritance.)

      @class ActionHandler
      @namespace Ember
      @private
    */
    const ActionHandler = Mixin.create({
      mergedProperties: ['actions'],

      /**
        The collection of functions, keyed by name, available on this
        `ActionHandler` as action targets.

        These functions will be invoked when a matching `{{action}}` is triggered
        from within a template and the application's current route is this route.

        Actions can also be invoked from other parts of your application
        via `ActionHandler#send`.

        The `actions` hash will inherit action handlers from
        the `actions` hash defined on extended parent classes
        or mixins rather than just replace the entire hash, e.g.:

        ```js
        App.CanDisplayBanner = Ember.Mixin.create({
          actions: {
            displayBanner(msg) {
              // ...
            }
          }
        });

        App.WelcomeRoute = Ember.Route.extend(App.CanDisplayBanner, {
          actions: {
            playMusic() {
              // ...
            }
          }
        });

        // `WelcomeRoute`, when active, will be able to respond
        // to both actions, since the actions hash is merged rather
        // then replaced when extending mixins / parent classes.
        this.send('displayBanner');
        this.send('playMusic');
        ```

        Within a Controller, Route or Component's action handler,
        the value of the `this` context is the Controller, Route or
        Component object:

        ```js
        App.SongRoute = Ember.Route.extend({
          actions: {
            myAction() {
              this.controllerFor("song");
              this.transitionTo("other.route");
              ...
            }
          }
        });
        ```

        It is also possible to call `this._super(...arguments)` from within an
        action handler if it overrides a handler defined on a parent
        class or mixin:

        Take for example the following routes:

        ```js
        App.DebugRoute = Ember.Mixin.create({
          actions: {
            debugRouteInformation() {
              console.debug("trololo");
            }
          }
        });

        App.AnnoyingDebugRoute = Ember.Route.extend(App.DebugRoute, {
          actions: {
            debugRouteInformation() {
              // also call the debugRouteInformation of mixed in App.DebugRoute
              this._super(...arguments);

              // show additional annoyance
              window.alert(...);
            }
          }
        });
        ```

        ## Bubbling

        By default, an action will stop bubbling once a handler defined
        on the `actions` hash handles it. To continue bubbling the action,
        you must return `true` from the handler:

        ```js
        App.Router.map(function() {
          this.route("album", function() {
            this.route("song");
          });
        });

        App.AlbumRoute = Ember.Route.extend({
          actions: {
            startPlaying: function() {
            }
          }
        });

        App.AlbumSongRoute = Ember.Route.extend({
          actions: {
            startPlaying() {
              // ...

              if (actionShouldAlsoBeTriggeredOnParentRoute) {
                return true;
              }
            }
          }
        });
        ```

        @property actions
        @type Object
        @default null
        @public
      */

      /**
        Triggers a named action on the `ActionHandler`. Any parameters
        supplied after the `actionName` string will be passed as arguments
        to the action target function.

        If the `ActionHandler` has its `target` property set, actions may
        bubble to the `target`. Bubbling happens when an `actionName` can
        not be found in the `ActionHandler`'s `actions` hash or if the
        action target function returns `true`.

        Example

        ```js
        App.WelcomeRoute = Ember.Route.extend({
          actions: {
            playTheme() {
               this.send('playMusic', 'theme.mp3');
            },
            playMusic(track) {
              // ...
            }
          }
        });
        ```

        @method send
        @param {String} actionName The action to trigger
        @param {*} context a context to send with the action
        @public
      */
      send(actionName, ...args) {
        if (this.actions && this.actions[actionName]) {
          let shouldBubble = this.actions[actionName].apply(this, args) === true;
          if (!shouldBubble) { return; }
        }

        let target = get(this, 'target');
        if (target) {
          assert(
            'The `target` for ' + this + ' (' + target + ') does not have a `send` method',
            typeof target.send === 'function'
          );
          target.send(...arguments);
        }
      },

      willMergeMixin(props) {
        assert('Specifying `_actions` and `actions` in the same mixin is not supported.', !props.actions || !props._actions);

        if (props._actions) {
          deprecate(
            'Specifying actions in `_actions` is deprecated, please use `actions` instead.',
            false,
            { id: 'ember-runtime.action-handler-_actions', until: '3.0.0' }
          );

          props.actions = props._actions;
          delete props._actions;
        }
      }
    });

    export default ActionHandler;

    export function deprecateUnderscoreActions(factory) {
      Object.defineProperty(factory.prototype, '_actions', {
        configurable: true,
        enumerable: false,
        set(value) {
          assert(`You cannot set \`_actions\` on ${this}, please use \`actions\` instead.`);
        },
        get() {
          deprecate(
            `Usage of \`_actions\` is deprecated, use \`actions\` instead.`,
            false,
            { id: 'ember-runtime.action-handler-_actions', until: '3.0.0' }
          );
          return get(this, 'actions');
        }
      });
    }