ExtJS 4.1 Call One Controller From Another

10,490

Solution 1

It makes sense to me to fire a custom event from the form and simply listen to it in both your controllers, like what you said here:

It seems like I should fire a unique event that is listened to by both controllers

// File: app/controller/Auth.js
attemptLogin : function() {
    var form = Ext.ComponentQuery.down('#loginpanel').form;
    if (form.isValid()) {
        form.submit({
        success : function(form, action) {
            // fire the event from the form panel
            form.owner.fireEvent('loginsuccess', form.owner);
        },

Then in each of your controllers you can listen to it with Controller#control, like this:

Ext.define('YourApp.controller.Auth', {
    extend: 'Ext.app.Controller',

    init: function() {
        var me = this; 

        me.control({

            '#loginpanel': {

                loginsuccess: me.someHandler

            }
        });
    },

    someHandler: function(form) {
        //whatever needs to be done
        console.log(form);
    }
}

And then add the same thing to your Quiz controller:

Ext.define('YourApp.controller.Quiz', {
    extend: 'Ext.app.Controller',

    init: function() {
        var me = this; 

        me.control({

            '#loginpanel': {

                loginsuccess: me.someOtherHandler

            }
        });
    },

    someOtherHandler: function(form) {
        //whatever needs to be done
        console.log(form);
    }
}

I've used this approach successfully in 4.1.0 and 4.1.1

Solution 2

It really should be

Assessor.controller.Auth.prototype.finishLogin.apply(this, arguments)

or something along these lines (in order to have a correct this reference that points to the 'owner' of the method, the controller object)

However, why do you use this unorthodox way to call the current controller's method. Just set the scope for the success callback, then call this.finishLogin().

form.submit({
    success : function(form, action) {
        // THIS IS THE FUNCTION FROM THE CURRENT CONTROLLER
        this.finishLogin();
        ...
    },
    scope: this
});

Also, you can retrieve another controller instance using Controller#getController.

this.getController('Assessor.controller.quiz').setupAssignment();

Then, if your controller methods are not depending on each other, you could make them both listen to the same event.

Another solution is to fire a custom event once the login is finished. You could do that on the application object

this.application.fireEvent('logincomplete');

and in your controller's init method:

this.application.mon('logincomplete', this.setupAssignment, this);

Please note that you cannot listen to those events via Controller#control - see Alexander Tokarev's blog post for a patch to Ext to achieve this.

Solution 3

There is no standard way to fire events between controllers, but it's possible with some custom hacks. See my recent blog post.

Share:
10,490

Related videos on Youtube

justinzane
Author by

justinzane

Recovering Novell / Microsoft SysAdmin becoming an OpenSource hack. Prefer C and Python on GNU/Linux.

Updated on September 14, 2022

Comments

  • justinzane
    justinzane over 1 year

    Note: I'm a total ignoramus regarding javascript.

    I've broken my ExtJS 4.1 MVC app out into several controllers like:

    /app/controller/Auth
        |          |Quiz
        |          |Result
        |          |Blah...
        |model/...
    

    I want to respond to an "event", not a DOM Event, rather a Ext.form.action.Submit.success event by calling functions in both my Auth and Quiz controllers. The summarized code for the first part is here:

    // File: app/controller/Auth.js
    attemptLogin : function() {
        var form = Ext.ComponentQuery.query('#loginpanel')[0].form;
        if (form.isValid()) {
            form.submit({
            success : function(form, action) {
                // THIS IS THE FUNCTION FROM THE CURRENT CONTROLLER
                Assessor.controller.Auth.prototype.finishLogin();
                // THIS IS THE FUNCTION FROM THE OTHER CONTROLLER
                Assessor.controller.Quiz.prototype.setupAssessment();
            },
    

    This works but feels wrong. Is there a proper way to do this? It seems like I should fire a unique event that is listened to by both controllers, but I can't understand how to do that with Ext.Event. Any guidance?

    Thanks! I'm really grateful for all the great ideas and advice.

  • mmigdol
    mmigdol over 11 years
    We use an approach similar to this, but because we don't like some of our events being bound to a specific view, we fire our events using Ext.Viewport.fireEvent("eventname"). Then you can listen for them in any controller using the viewport reference.
  • Alex Tokarev
    Alex Tokarev over 11 years
    @mmigdol, how do you unit-test your controllers if you fire events from Viewport?
  • mmigdol
    mmigdol over 11 years
    @AlexanderTokarev, just fire events from the Viewport in the test harness...or maybe I'm misunderstanding your question?
  • Alex Tokarev
    Alex Tokarev over 11 years
    @mmigdol, This implies that in order to test a Controller, you need to instantiate the Viewport and all its children. Or do you use some kind of test-only Viewport?
  • mmigdol
    mmigdol over 11 years
    @AlexanderTokarev, that's right. My unit tests are normally standalone apps that instantiate a single view and/or its associated controller
  • abarisone
    abarisone over 8 years
    Could you please elaborate more your answer adding a little more description about the solution you provide?
  • Asanda Lamba
    Asanda Lamba over 8 years
    Don't understand the question. If read above, this is how you call function from different controller. You need to specify where is the file. eg