rosebrit3
rosebrit3

Reputation: 523

One view and multiple controller actions for the same button in EXTJS

Am having a delete button in my EXTJS Application. On clicking the button, am opening a confirmation form, asking the user are they sure to delete the item. The delete button is a part of many forms in my Application. And irrespective of the form being used, am opening the confirmation window.

And on clicking the yes button in the confirmation window, i want to do some action. But these actions have to be specific to the form that was opened first.So, am confused about how to use the same view, the same button, but different actions depending upon the first form that was opened.

View: This is the window that opens on clicking the delete button in any of the forms

  Ext.define('app.view.GenMessageWin', {
extend : 'Ext.panel.Panel',
alias : 'widget.genmessagewin',

  var fp = {
        xtype : 'panel',
        itemId : 'MSGPANEL',
        width : Width,
        height : 150,
        cls : 'msg effect1',
        layout : 'form',
        border : false,
        items : [{
            xtype : 'panel',
            //cls : 'winTitle',
            html : msgTxt,
            border : 0
        }, {
            xtype : 'form',
            itemId : 'MSGFORM',
            border : false,
            title : '',
            buttonAlign : 'center',
            fieldDefaults : {
                msgTarget : 'side',
                labelWidth : 110,
                size : 30
            },

            buttons : [{
                text : LANG.BTYES,
                iconCls : 'icon-tick-tb',
                iconAlign : 'right',
                cls : 'tip-btn',
                action : 'delete',
                id : 'BTYES'
            }, {
                text : LANG.BTNO,
                iconCls : 'icon-cross-tb',
                iconAlign : 'right',
                cls : 'tip-btn',
                action : 'notDelete',
                id : 'BTNO'
            } ]

Controller

        init : function() {

         this.control({

        'button[action = delete]' : {
            click : this.delete
        },
        'button[action = notDelete]' : {
            click : this.notDelete
        },

So, in the delete action, we have to determine which form has been opened in the first place, and then delete the data accordingly.

Upvotes: 1

Views: 4177

Answers (4)

rosebrit3
rosebrit3

Reputation: 523

The final solution that i used was to declare variables using the global namespace so that they can be accessed from anywhere. On opening the first form, i get the data from the form using the record variable, and assign them a global name like

App1.Var1 = record.data.id;

And, on opening the delete window, these variables can be accessed by App1.Var1 when the buttons are clicked.

Upvotes: 0

Dmitry Pashkevich
Dmitry Pashkevich

Reputation: 13516

I think you should embed the 'confirmation' functionality inside the button, i.e. create your own ConfirmButton class that would first fire a dialog upon pressing and executing the passed handler only if the dialog exited with "yes".

Here is the example implementation:

Ext.define('My.ConfirmButton',  {
    extend: 'Ext.button.Button',
    alias: 'widget.confirmbutton',

    dlgConf: {
        title: 'Are you sure?',
        msg: 'Are you sure you want to delete this?',
        buttons: Ext.Msg.YESNO,
        closable: false
    },

    initComponent: function() {
        this.callParent(arguments);
        // remember the originally passed handler
        this.origHandler = this.handler;
        this.origScrope = this.scope;

        // override current handler to fire confirmation box first
        this.handler = this.confirmHandler;
        this.scope = this;
    },

    confirmHandler: function(me, e) {
        // show dialog and call the original handler only on 'yes'
        Ext.Msg.show(Ext.applyIf({
            fn: function(buttonId) {
                if(buttonId == 'yes') {
                    me.origHandler && me.origHandler.call(me.origScope || me, me, e)
                }
            },
            scope: me
        }, this.dlgConf))
    },

    // Method used to dynamically reassign button handler
    setHandler: function(handler, scope) {
        // remember the originally passed handler
        this.origHandler = this.handler;
        this.origScrope = this.scope;

        // override current handler to fire confirmation box first
        this.handler = this.confirmHandler;
        this.scope = this;

        return this;
    },
});

Here is the sample usage:

Ext.create('My.ConfirmButton', {
    text: 'Delete me',
    renderTo: Ext.getBody(),
    handler: function() {
        alert('Aww, you deleted something! :(')
    }
});

As you see, the confirmation logic is hidden from the outside world, you use this button exactly like you would use a regular Ext.Button (by passing a handler to it). Also, you can override the configuration of the dialog that the button fires (you may want to adjust it to your needs, e.g. allow passing record name to the dialog for a friendlier UI).

Note that the code isn't thoroughly tested, some cases might be left uncovered.

UPD. You need to add an alias (former xtype) to the component class definition so you can use it in ComponentQuery in your controller code, e.g.

this.control({
    'confirmbutton[action = delete]' : {
        click : this.delete
    },
    'confirmbutton[action = notDelete]' : {
        click : this.notDelete
    }
})

Upvotes: 1

Evan Trimboli
Evan Trimboli

Reputation: 30082

You have 3 options:

1) Make the selector more specific:

'form1 button[action=delete]': {
    click: this.form1Delete
},

form1Delete: function(){
    this.showMsg(function() {
        // form 1 delete
    });
}

2) Traverse back up the component hierarchy and find the open form

onDelete: function(btn) {
    var form = btn.up('form'); // find an xtype form or subclass
    if (form.someCondition) {
       //foo
    } else {
        //bar
    }
}

3) As suggested by Dmitry. You'll need to convert it over to 'MVC style'.

Ext.define('ConfirmButton', {
    extend: 'Ext.button.Button',

    title: '',
    msg: '',

    requires: ['Ext.window.MessageBox'],

    initComponent: function(){
        this.callParent();
        this.on('click', this.handleClick, this);
    },

    handleClick: function(){
        Ext.MessageBox.confirm(this.title, this.msg, this.checkResponse, this);
    },

    checkResponse: function(btn){
        if (btn == 'yes') {
            this.fireEvent('confirm', this);
        }
    }
});

Ext.onReady(function(){

    var btn = new ConfirmButton({
        renderTo: document.body,
        text: 'Foo',
        title: 'Should I',
        msg: 'Are you sure'
    });

    btn.on('confirm', function(){
        console.log('Do something');
    })

});

Upvotes: 2

sra
sra

Reputation: 23975

I am doing something similar; I simply use the native Ext.Msg class

Controller code

,onDelete: function() {
    var me = this;
    Ext.Msg.show({
        title:'Really shure?',
        msg: 'Really wanna do this?',
        buttons: Ext.Msg.YESNO,
        icon: Ext.Msg.QUESTION,
        closable: false,
        fn: function(btn) {
            if (btn == 'yes') {
                me.deleteRecord();
            }
        },
        scope: me
    });
}
,deleteRecord: function() {
    var me = this,
        store = Ext.StoreMgr.lookup('datastore');
    store.remove(me.selectedRecord);
    store.sync();
}

I would recommend you to keep all logic concerning this within the controller. I your case it'seems that's no problem, cause you just catching the button-events. You problem may be that all controllers catch these, if you are using totally the same window.

You can solve this for example by creating the action property value dynamically when creating the window. Like action='onDeleteCar'

Upvotes: 1

Related Questions