#

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

# File: packages/ember-views/lib/mixins/action_support.js

    /**
     @module ember
     @submodule ember-views
    */
    import { inspect } from 'ember-utils';
    import { Mixin, get, isNone, assert } from 'ember-metal';
    import { MUTABLE_CELL } from '../compat/attrs';

    function validateAction(component, actionName) {
      if (actionName && actionName[MUTABLE_CELL]) {
        actionName = actionName.value;
      }

      assert(
        'The default action was triggered on the component ' + component.toString() +
        ', but the action name (' + actionName + ') was not a string.',
        isNone(actionName) || typeof actionName === 'string' || typeof actionName === 'function'
      );
      return actionName;
    }

    /**
     @class ActionSupport
     @namespace Ember
     @private
    */
    export default Mixin.create({
      /**
        Calls an action passed to a component.

        For example a component for playing or pausing music may translate click events
        into action notifications of "play" or "stop" depending on some internal state
        of the component:

        ```javascript
        // app/components/play-button.js
        export default Ember.Component.extend({
          click() {
            if (this.get('isPlaying')) {
              this.sendAction('play');
            } else {
              this.sendAction('stop');
            }
          }
        });
        ```

        The actions "play" and "stop" must be passed to this `play-button` component:

        ```handlebars
        {{! app/templates/application.hbs }}
        {{play-button play=(action "musicStarted") stop=(action "musicStopped")}}
        ```

        When the component receives a browser `click` event it translate this
        interaction into application-specific semantics ("play" or "stop") and
        calls the specified action.

        ```javascript
        // app/controller/application.js
        export default Ember.Controller.extend({
          actions: {
            musicStarted() {
              // called when the play button is clicked
              // and the music started playing
            },
            musicStopped() {
              // called when the play button is clicked
              // and the music stopped playing
            }
          }
        });
        ```

        If no action is passed to `sendAction` a default name of "action"
        is assumed.

        ```javascript
        // app/components/next-button.js
        export default Ember.Component.extend({
          click() {
            this.sendAction();
          }
        });
        ```

        ```handlebars
        {{! app/templates/application.hbs }}
        {{next-button action=(action "playNextSongInAlbum")}}
        ```

        ```javascript
        // app/controllers/application.js
        App.ApplicationController = Ember.Controller.extend({
          actions: {
            playNextSongInAlbum() {
              ...
            }
          }
        });
        ```

        @method sendAction
        @param [action] {String} the action to call
        @param [params] {*} arguments for the action
        @public
      */
      sendAction(action, ...contexts) {
        let actionName;

        // Send the default action
        if (action === undefined) {
          action = 'action';
        }
        actionName = get(this, `attrs.${action}`) || get(this, action);
        actionName = validateAction(this, actionName);

        // If no action name for that action could be found, just abort.
        if (actionName === undefined) { return; }

        if (typeof actionName === 'function') {
          actionName(...contexts);
        } else {
          this.triggerAction({
            action: actionName,
            actionContext: contexts
          });
        }
      },

      send(actionName, ...args) {
        let action = this.actions && this.actions[actionName];

        if (action) {
          let shouldBubble = action.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);
        } else {
          assert(`${inspect(this)} had no action handler for: ${actionName}`, action);
        }
      }
    });