PDA

View Full Version : How to locally access Buttons of a FormPanel?



gero013
22 Jan 2011, 11:50 PM
Hello,

currently my buttons have an id and I use Ext.getCmp(id) to access them. That works so far.
Now that the master/detail is working, I'd like to remove the id and change access to kindof getComponent(name).
I already tried it, but it did not work.
From the manual I know, that buttons are not items so far and getComponent only works on items. Then I read, that buttons will go into a footer Toolbar, but when I check the dom - there's no toolbar. Not in the FormPanel, nor in the Fieldset.

I create the buttons like this:
FormPanel({
items: [{
xtype: 'fieldset',
items: [{
...
}],
buttons: [{
... my button-definitions
}]
}]
}) background: I have i.e. 5 DetailPanels attached to the master/detail and I'd like each of it have a 'save' and a 'delete' button. Currently all have unique ids, but I would like to cleanup global namespace and allow each 'save' button have the same itemId

kind regards

Gero

25 Jan 2011, 10:57 AM
If you have a few moments try the following screencast: http://tdg-i.com/392/ext-js-screencast-the-dangers-of-ext-getcmp

jratcliff
25 Jan 2011, 11:22 AM
you can use the 'ref' property so you can inject a named reference for each button into the FormPanel

http://dev.sencha.com/deploy/dev/docs/?class=Ext.Button

gero013
25 Jan 2011, 8:37 PM
Hello,

thanks for your time and support!

@jgarcia
I'm working on linux and flash is completely disabled on all my machines - so no way for screencast or the like.
Additionally I'd like to read - for me its the better way to learn anything.

@jratcliff
Thanks for the hint with 'ref' - looks like the missing link, I was searching for. But it did not work for me (means, I did not find the ref or refOwner from firebug) and I realized, that I have a big point of misunderstanding!
Meanwhile I read, that the context of JS-functions differ dependant to the caller.
So from my understanding the methods are not really methods, but simple functions, that can use a 'this' keyword.
So how can I implement a callback/listener, that gets the declared object beeing the this instance instead of having the caller being this?

Is there any reading/tutorial for real OO-coders to understand the JS-way of doing things?

kind regards

Gero

Barzoy
26 Jan 2011, 6:13 AM
var submitButton = null;
var closeButton = null;

var myForm = new Ext.FormPanel({
buttons: [{
text: 'Login',
handler: function() {
// submit it on click
},
listeners: {
added: function(button) {
submitButton = button;
}
}
},{
text: 'Close',
handler: function() {
// close it on click
},
listeners: {
added: function(button) {
closeButton = button;
}
}
}]
});

submitButton.setText('Imma teh submit button, yo can access me via "submitButton" variable nao');

Works fine for me.

This also works.

var myForm = new Ext.FormPanel({
buttons: [{
text: 'Login',
itemId: 'submitButton',
handler: function() {
// submit it on click
}
},{
text: 'Close',
itemId: 'closeButton',
handler: function() {
// close it on click
}
}]
});

myForm.getFooterToolbar().getComponent('submitButton').setText('Gotcha!');

26 Jan 2011, 6:16 AM
Gero, chapters 15, 16 and 17 of my book describe how to deal w/ problems like these.

gero013
26 Jan 2011, 9:44 PM
Hello,

thank you all for your support!

May be my problem is quite different and I only don't know to name it right.
I'd like to do something like the second sample of Barzoy, but when I call getBottomToolbar() I get the error getBottomToolbar() is undefined ...

May be I should go a bit deeper, explaining what I'd like to do:
At toplevel, my app looks like this:
Ext.onReady(function() {
var cc = Ext.getCmp('vacc');
var rm = new VA.app.RecordingManager();

cc.add(rm);
cc.activate(0);

rm.addActionPage(new VA.app.RecordingDetail());
rm.doLayout();
}); cc is a tabbed container - and not of interest here.
RecordingManager is derived from MasterDetails, which is a Panel with a grid and a container for the detail pages (ActionPage). The RecordingDetail is derived from FormPanel and plugged into the container of MasterDetails. The grid has a RowSelectionModel with a listener. That listener is a function from MasterDetail, but attached as RecordingManager.selectRow
That listener function (from MasterDetail) determines the form and loads the selected record from grid into the form.
The formloaded event seems to be fired too early, so I'd like to simulate that event.
The form starts with its buttons disabled. After form loading, the buttons should get enabled, but I don't want to code that in MasterDetail. So from the selectRow-trigger-function (where I load the form), I call a formLoaded of the ActionPage (derived from FormPanel).
Each of my components now have an itemId, so I can identify that component in the dom-viewer of firebug.
The formLoaded function of RecordingDetails is this:

formLoaded: function() {
console.log(this);
this.getFooterToolbar().getComponent('btSaveRec').enable();
// Ext.getCmp('btSaveRec').enable();
Ext.getCmp('btDelRec').enable();
} The output of console.log(this) shows, that this is the RecordingDetails (FormPanel), where the buttons are defined with a button section.
The approach with the additional vars for the buttons might work, but I think it is not quite better than Ext.getCmp - so I'd like to avoid it - if possible.

May be, I'm trying something that won't work - I don't know.
So any comment, that shines a light on my error/misunderstanding is very appreciated.

kind regards

Gero

Barzoy
27 Jan 2011, 12:01 AM
Clarify please what exactily is undefined:
1. getFooterToolabr function of "this"
2. result of this.getFooterToolbar() call

In the first case getFooterToolbar function is undefined because "this" is not an instance of Ext.FromPanel directly and not is an instance of any of its child classes.

If "this" has a getFooterToolbar method, but that method returns nothing, so "this" has no footer toolbar at all.
Footer toolbar is automaticaly created by Ext.FormPanel when it has configured buttons like in my second example. So, code like

var myForm = new Ext.FormPanel({
buttons: [{
text: 'Login',
itemId: 'submitButton',
}]
});
myForm.getFooterToolbar().getComponent('submitButton').setText('Gotcha!');
works fine but

var myForm = new Ext.FormPanel({

});
myForm.getFooterToolbar().getComponent('submitButton').setText('Gotcha!');
throws an exception

TypeError: myForm.getFooterToolbar() is undefined

So there is 2 reasons why your form has no footer toolbar:
1. buttons are created manualy, not via buttons: {} config section
2. your RecordingDetails class overrides some original Ext.FormPanel class methods, which are responsible for creation of footer toolbar. Does your RecordingDetails class has any of the following methods defined: initComponent, createFbar, createToolbar. If so, I hope you do not forget to call parent methods.

gero013
27 Jan 2011, 12:41 AM
Hello,

thanks a lot for your attention!


Clarify please what exactily is undefined If I understand firebug right, the message 'xyz is undefined' means, the return value of that function, or the content of the variable is undefined. If a non-existing function will be called, the error message is 'function xyz does not exist' or similar.

So I gonna post the classes
First the baseclass ActionPanel
Ext.ns('VA.support');

VA.support.ActionPanel = Ext.extend(Ext.form.FormPanel, {
srvname: 'std',
frame: true,
labelAlign: 'left',
title: 'ActionPanel',

initComponent: function() {
VA.support.ActionPanel.superclass.initComponent.apply(this, arguments);
},

execForm: function(cmd) {
var f = this.getForm();

f.findField('sid').setValue(f.findField('id').getValue());
f.getEl().dom.action = VA.base.backend.URL + '/' + this.srvname + '?' + cmd;
f.getEl().dom.method = 'POST';
f.submit();
}
});...and now the derived class RecordingDetail

Ext.ns('VA.app');

VA.app.RecordingDetail = Ext.extend(VA.support.ActionPanel, {
srvname: 'rec',
title: 'edit Details',
itemId: 'recordingDetails',

initComponent: function() {
Ext.apply(this, {
items: [{
contentEl: this.srvname + 'Details',
xtype: 'fieldset',
labelWidth: 100,
defaults: { width: 190, border: false },
defaultType: 'textfield',
autoHeight: true,
border: false,
iconCls: 'va-icon-rec',
items: [{
...
}],
buttons: [{
text: 'Save',
id: 'btSaveRec',
itemId: 'btSaveRec',
ref: '../btSaveRec',
disabled: true,
iconCls: 'va-icon-save'
},{
text: 'Delete',
id: 'btDelRec',
itemId: 'btDelRec',
ref: '../btDelRec',
disabled: true,
iconCls: 'va-icon-delete'
}]
}]
});

VA.app.RecordingDetail.superclass.initComponent.apply(this, arguments);
},

deleteRecord: function() {
var id = getForm().findField('id').getValue();

Ext.MessageBox.confirm('Confirm',
'really delete #' + id + '?',
function(b) {
//TODO: next call does not work, cause 'this' is the wrong object/class
this.execForm('c=rd');
Ext.getCmp('btSaveRec').disable();
Ext.getCmp('btDelRec').disable();
});
},

saveRecord: function() {
console.log(arguments[0]);
console.log(arguments[1]);
console.log(this.refOwner);
// rd = this.refOwner;
// if (rd != null) rd.execForm('c=sd');
// this.disable();
},

formLoaded: function() {
console.log(this); // shows itemId='recordingDetails'
// TODO: the failing line: 'getFooterToolbar() is undefined'
// this.getFooterToolbar().getComponent('btSaveRec').enable();

Ext.getCmp('btSaveRec').enable();
Ext.getCmp('btDelRec').enable();
}
});by the way: the buttons from the form panel do not really look like being part of a toolbar

kind regards

Gero

Barzoy
27 Jan 2011, 2:07 AM
So, as I said, your FormPanel has no footer toolbar, but fieldset inside it has. So you can get that buttons out of fieldset to place them inside your panel. Or you can set itemId property for fieldset, to be able to get reference to it via getComponent('myFieldsetItemId').

Sorry I've deleted some parts of your code because they are no related to this issue, there is only important lines left. Here is working example


Ext.ns('VA.support');

VA.support.ActionPanel = Ext.extend(Ext.form.FormPanel, {

initComponent: function() {
VA.support.ActionPanel.superclass.initComponent.apply(this, arguments);
}

});

Ext.ns('VA.app');

VA.app.RecordingDetail = Ext.extend(VA.support.ActionPanel, {

initComponent: function() {
var config = {
items: [{
xtype: 'fieldset',
itemId: 'mainFieldset',
buttons: [{
text: 'Save',
itemId: 'btSaveRec',
disabled: true
},{
text: 'Delete',
itemId: 'btDelRec',
disabled: true
}]
}]
};
Ext.apply(this, config);
Ext.apply(this.initialConfig, config);

VA.app.RecordingDetail.superclass.initComponent.apply(this, arguments);
},

formLoaded: function() {
this.getComponent('mainFieldset').getFooterToolbar().getComponent('btSaveRec').setText('Hello');
}

});

var myForm = new VA.app.RecordingDetail({
renderTo: Ext.getBody()
});
myForm.formLoaded();

Barzoy
27 Jan 2011, 2:11 AM
by the way: the buttons from the form panel do not really look like being part of a toolbar

Yep, but they are. Just look into /ext/src/widgets/Panel.js

Here is a part of Ext.Panel.prototype.initComponent method

...
if(this.buttons){
this.fbar = this.buttons;
this.buttons = null;
}
if(this.fbar){
this.createFbar(this.fbar);
}
...

gero013
27 Jan 2011, 4:42 AM
Hello,


So, as I said, your FormPanel has no footer toolbar, but fieldset inside it has.
Great! Thanks a lot for pointing this out!
I did not realize, that a fieldset could have a toolbar.

Now I changed the button definition to the panel and everythings works fine :)
... additionally it now looks as expected B)

kind regards

Gero