Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How do I call an action method on Controller from the outside, with the same behavior by clicking {{action}}

Tags:

ember.js

Please look at this code...

```

            App.BooksRoute = Ember.Route.extend({
                model:  return function () {
                    return this.store.find('books');
                }
            });

            App.BooksController = Ember.ArrayController.extend({
                actions: {
                    updateData: function () {
                        console.log("updateData is called!");
                        var books = this.filter(function () {
                            return true;
                        });
                        for(var i=0; i<books.length; i++) {
                            //doSomething…
                        }
                    }
                }
            });

```

I want to call the updateData action on BooksController from the outside.

I tried this code.

App.__container__.lookup("controller:books").send('updateData');

It works actually. But, in the updateData action, the this is different from the one in which updateData was called by clicking {{action 'updateData'}} on books template.

In the case of clicking {{action 'updateData'}}, the this.filter() method in updateData action will return books models. But, In the case of calling App.__container__.lookup("controller:books").send('updateData');, the this.filter() method in updateData action will return nothing.

How do I call the updateData action on BooksController from the outside, with the same behavior by clicking {{action 'updateData'}}.

I would appreciate knowing about it.

(I'm using Ember.js 1.0.0)

like image 403
EMADURANDAL Avatar asked Sep 18 '13 04:09

EMADURANDAL


3 Answers

You can use either bind or jQuery.proxy. bind is provided in JS since version 1.8.5, so it's pretty safe to use unless you need to support very old browsers. http://kangax.github.io/es5-compat-table/

Either way, you're basically manually scoping the this object.

So, if you have this IndexController, and you wanted to trigger raiseAlert from outside the app.

App.IndexController = Ember.ArrayController.extend({
  testValue : "fooBar!",
  actions : {
    raiseAlert : function(source){
      alert( source + " " + this.get('testValue') );
    }
  }
});

With bind :

function externalAlertBind(){
  var controller = App.__container__.lookup("controller:index");
  var boundSend = controller.send.bind(controller);
  boundSend('raiseAlert','External Bind');
}

With jQuery.proxy

function externalAlertProxy(){
  var controller = App.__container__.lookup("controller:index");
  var proxySend = jQuery.proxy(controller.send,controller);
  proxySend('raiseAlert','External Proxy');
}

Interestingly this seems to be OK without using either bind or proxy in this JSBin.

function externalAlert(){
  var controller = App.__container__.lookup("controller:index");
  controller.send('raiseAlert','External');
}

Here's a JSBin showing all of these: http://jsbin.com/ucanam/1080/edit

[UPDATE] : Another JSBin that calls filter in the action : http://jsbin.com/ucanam/1082/edit

[UPDATE 2] : I got things to work by looking up "controller:booksIndex" instead of "controller:books-index".

Here's a JSBin : http://jsbin.com/ICaMimo/1/edit

And the way to see it work (since the routes are weird) : http://jsbin.com/ICaMimo/1#/index

like image 184
Jeremy Green Avatar answered Oct 21 '22 05:10

Jeremy Green


This solved my similar issue

Read more about action boubling here: http://emberjs.com/guides/templates/actions/#toc_action-bubbling

SpeedMind.ApplicationRoute = Ember.Route.extend({
    actions: {
        // This makes sure that all calls to the {{action 'goBack'}}
        // in the end is run by the application-controllers implementation
        // using the boubling action system. (controller->route->parentroutes)
        goBack: function() {
            this.controllerFor('application').send('goBack');
        }
    },
};

SpeedMind.ApplicationController = Ember.Controller.extend({
    actions: {
        goBack: function(){
            console.log("This is the real goBack method definition!");
        }
    },
});
like image 31
consideRatio Avatar answered Oct 21 '22 05:10

consideRatio


You could just have the ember action call your method rather than handling it inside of the action itself.

App.BooksController = Ember.ArrayController.extend({
            actions: {
                fireUpdateData: function(){
                    App.BooksController.updateData();
                }
            },

            // This is outside of the action
            updateData: function () {
                    console.log("updateData is called!");
                    var books = this.filter(function () {
                        return true;
                    });
                    for(var i=0; i<books.length; i++) {
                        //doSomething…
                    }
                }
        });

Now whenever you want to call updateData(), just use

App.BooksController.updateData();

Or in the case of a handlebars file

{{action "fireUpdateData"}}
like image 39
stealthysnacks Avatar answered Oct 21 '22 05:10

stealthysnacks