Akshay Rawat
Akshay Rawat

Reputation: 4784

Using {{action}} to target an event in a different route

Assuming I have a route with an event like

App.FooRoute = Ember.Route.extend({
  events: {
    anAction: function(){
    }
  }
})

How do I trigger it from the view of another route/controller ?

<a {{action anAction target='???'}}> a link </a>

Upvotes: 3

Views: 767

Answers (2)

Duncan Walker
Duncan Walker

Reputation: 2201

As explained in the Ember Docs, you can use a built in mixin called Ember.ViewTargetActionSupport to send actions to a different controller or view or route within your app.

A simple way to handle your problem is as follows:

  1. The event called in the template is handled in the current view
  2. This view has Em.ViewTargetActionSupport mixed in
  3. This event, written in your view, calls a this.triggerAction function specifying the action you are trying to call in a different view/controller/route (the target)

The current template:

<a {{action 'actionInView' target='view'}}>Click me</a>

The View:

App.CurrentView = Em.View.extend(Em.ViewTargetActionSupport, { // Note the mixin
  actions: { // Actions hash
    actionInView: {
      this.triggerAction({ // Without a target this will bubble through the routes
        action: 'theActionToCall', // Name of the action you *actually* want to call
        target: App.TargetController, // Or whatever the name of your target is
      });
    },
  },
});

The Target Controller:

App.TargetController = Em.ObjectController.extend({
  actions: {
    theActionToCall: {
      // This is where you do the action stuff that you *actually* are trying to do
    },
  },
});

Essentially, the action called actionInView does nothing but call the action you actually want but can't access because it's in a different part of your application. I you don't specify a target then you can place the action on a parent route, or the application route, and it will get called.

Upvotes: 0

James A. Rosen
James A. Rosen

Reputation: 65242

Let's say you have routes like this:

App.Router
  |
  + FooRoute
  |
  + BarRoute

What would it mean to send an action from the FooRoute to the BarRoute? The user has gone to /foo, so the FooModel, FooController, and FooView have been initialized, but the Bar* ones haven't. What would the action do?

Case 1: The Action Manipulates a Bar

In this case, having a BarModel around is a prerequisite for the FooRoute. The most Ember-like way to solve this is to use nested routes:

App.Router.map(function() {
  this.resource('bar', function() {
    this.route('foo');
  }
});

The user goes to /bars/123/foo and click on the link, triggering anAction. Ember will automatically bubble that action up the route hierarchy, so you can simply define anAction on BarRoute.

Case 2: The Action Needs no Bar

In this case, having a BarModel is unnecessary. anAction does some stuff that isn't really Foo-related, but nor is it Bar-related. We can use the same bubbling trick, but instead of defining anAction on BarRoute, we define it on the main router.

Case 3: The Action Needs a Global Object

Let's say that the action needs the "current user." This case is much like #2 in that you don't need to nest routes. It does, however require you to have a globally-addressable controller like App.currentUserController. You can directly specify this as the target of the {{action}}.

Case 4: You really want to target the BarController

If none of the above options seem quite right, you can use controllerFor to set a barController property on the fooController:

App.FooRoute = Ember.Route.extend({
  setupController: function(controller) {
    var barController = this.controllerFor('bar');
    controller.set('barController', barController);
  }
});

Then you can do {{action anAction target=barController}}.

Summary

Ember will automatically try the action against the controller, then bubble up the route hierarchy. If models depend on other models, you may need nested routes or global controllers to ensure that your prerequisites are hooked up.

Upvotes: 2

Related Questions