PDA

View Full Version : toolbar button extension and xtype shows undefined



josh803316
21 Feb 2009, 6:04 PM
I have the an extended toolbar button with a registered xtpe. I then attempt to apply the button to a toolbar in an extended panel. When I render the toolbar I see the button for the xtype as undefined.



app.toolBtnExportFile = Ext.extend(Ext.Toolbar.Button, {

initComponent:function() {
Ext.apply(this, {
text:'Export File',
handler: export_file
}); // e/o apply

ocmg.toolBtnExportFile.superclass.initComponent.apply(this, arguments);
} // e/o function initComponent

,onRender:function() {
ocmg.toolBtnExportFile.superclass.onRender.apply(this, arguments);
} // e/o function onRender
}); // e/o extend

// register xtype
Ext.reg('toptoolbarexportfile', app.toolBtnExportFile);


I then make a call to the xtype to lazily instantiate it inside an extended Panel


Ext.applyIf(this, {

title:'Example Title',
tbar: [
{ text: 'Commit' },
"-",
{ text: 'Resync' },
"-",
{
text: 'Export',
menu: {
items: [
{ xtype: 'toptoolbarexportfile' }
]
}

},
"-"
]
// config goes on here for rest of panel
});

mjlecomte
21 Feb 2009, 6:12 PM
Post the actual firebug stacktrace.

josh803316
21 Feb 2009, 6:18 PM
There is no stack trace, I don't get any error in firebug, I just see the button rendered in the drop down menu as 'undefined' and nothing happens when I click it.

mjlecomte
21 Feb 2009, 6:24 PM
And what happens if you pass the text along with that xtype?

Is that handler in global scope or something?

You could always post a working showcase...
http://extjs.com/learn/Ext_Forum_Help#Posting_a_working_showcase

josh803316
21 Feb 2009, 6:44 PM
If I pass text I definitely get the name with the button but the handler still doesn't work which leads me to believe that the config options for the xtype simply aren't passed at all. Even if I do a simple local onClick associated with the config for the button nothing happens. (Although my logic may be off here) I'll see if I can post an example.

I even tried this to no avail:


app.toolBtnExportFile = Ext.extend(Ext.Toolbar.Button, {
initComponent:function() {
Ext.apply(this, {
text:'Export File'

}); // e/o apply
app.toolBtnExportFile.superclass.initComponent.apply(this, arguments);

} // e/o function initComponent
,onRender:function() {
app.toolBtnExportFile.superclass.onRender.apply(this, arguments);
},
onClick:function(){
Ext.Msg.show({
title: 'TBD',
msg: 'this feature coming soon...',
width: 300,
buttons: Ext.MessageBox.OK,
icon: Ext.MessageBox.INFO
});
}
}); // e/o extend

// register xtype
Ext.reg('toptoolbarexportfile', app.toolBtnExportFile);

josh803316
21 Feb 2009, 6:59 PM
Sorry this may have typos I will fix later when I return.



<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
<title id='title'>Title</title>

<!-- ** CSS ** -->
<!-- base library -->
<link rel="stylesheet" type="text/css" href="../../resources/css/ext-all.css" />

<!-- overrides to base library -->


<!-- ** Javascript ** -->
<!-- base library -->
<script type="text/javascript" src="../../adapter/ext/ext-base.js"></script>
<script type="text/javascript" src="../../ext-all-debug.js"></script>


<!-- overrides to base library -->

<!-- extensions -->
Ext.ns('app')
app.toolBtnExportFile = Ext.extend(Ext.Toolbar.Button, {
initComponent:function() {
Ext.apply(this, {
text:'Export File'

}); // e/o apply
app.toolBtnExportFile.superclass.initComponent.apply(this, arguments);

} // e/o function initComponent
,onRender:function() {
console.log('rendered');
app.toolBtnExportFile.superclass.onRender.apply(this, arguments);
},
onClick:function(){
Ext.Msg.show({
title: 'TBD',
msg: 'this feature coming soon...',
width: 300,
buttons: Ext.MessageBox.OK,
icon: Ext.MessageBox.INFO
});
}
}); // e/o extend

// register xtype
Ext.reg('toptoolbarexportfile', app.toolBtnExportFile);

app.SinglePanel = Ext.extend(Ext.Panel, {
// override initComponent
initComponent: function() {
// used applyIf rather than apply so user could
// override the defaults
Ext.applyIf(this, {
title:'Example',
header:true,

tbar: [
{ text: 'Commit' },
"-",
{

text: 'Export',
menu: {
items: [
{ xtype: 'toptoolbarexportfile' }

]
}

},
"-"
],
layout:'fit',

items: []
});
// call the superclass's initComponent implementation
app.SinglePanel.superclass.initComponent.call(this);
},
// override initEvents
initEvents: function() {
// call the superclass's initEvents implementation
app.SinglePanel.superclass.initEvents.call(this);

}

});
// register an xtype with this class
Ext.reg('singlepanel', app.SinglePanel);
<!-- page specific -->
app.app = function() {
return {
// public properties, e.g. strings to translate
// public methods
init: function() {
Ext.state.Manager.setProvider(new Ext.state.CookieProvider());

var elog = new eventlog.EventLog("south");
elog.write("gOCM started");
elog.write("Server sync complete");

var tools = [{
id:'gear',
handler: function(){
Ext.Msg.alert('Message', 'The Settings tool was clicked.');
}
},{
id:'close',
handler: function(e, target, panel){
panel.ownerCt.remove(panel, true);
}
}];



var singlePanel = new app.singlePanel({});

}


};
}
<script type="text/javascript">
Ext.BLANK_IMAGE_URL = '../../resources/images/default/s.gif';

Ext.onReady(app.app.init, app.app); //end onReady
</script>

</head>
<body>
</body>
</html>

mjlecomte
22 Feb 2009, 6:25 AM
Yeah, that wouldn't even run, had errors. I modified it, taking out extra code and the text and handler worked.

josh803316
22 Feb 2009, 8:45 AM
Thanks, sorry about the errors I had to run out the door and didn't have time to test it. Anything major that you changed because mine still isn't rendering?

josh803316
22 Feb 2009, 10:08 AM
I cleaned it up so it would properly render the issue I'm seeing. With the following code I still undefined....mjlecomte, what did you change to get this to render the button correctly?



<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
<title id='title'>Title</title>

<!-- ** CSS ** -->
<!-- base library -->
<link rel="stylesheet" type="text/css" href="../../resources/css/ext-all.css" />

<!-- overrides to base library -->


<!-- ** Javascript ** -->

<!-- base library -->
<script type="text/javascript" src="../../adapter/ext/ext-base.js"></script>
<script type="text/javascript" src="../../ext-all-debug.js"></script>


<!-- overrides to base library -->

<!-- extensions -->
<script type="text/javascript">
Ext.ns('app');
app.toolBtnExportFile = Ext.extend(Ext.Toolbar.Button, {
initComponent:function() {
Ext.apply(this, {
text:'Export File',
handler: this.onClick

}); // e/o apply
app.toolBtnExportFile.superclass.initComponent.apply(this, arguments);

} // e/o function initComponent
,onRender:function() {
console.log('rendered');
app.toolBtnExportFile.superclass.onRender.apply(this, arguments);
},
onClick:function(){
Ext.Msg.show({
title: 'TBD',
msg: 'this feature coming soon...',
width: 300,
buttons: Ext.MessageBox.OK,
icon: Ext.MessageBox.INFO
});
}
}); // e/o extend

// register xtype
Ext.reg('toptoolbarexportfile', app.toolBtnExportFile);

app.SinglePanel = Ext.extend(Ext.Panel, {
// override initComponent
initComponent: function() {
// used applyIf rather than apply so user could
// override the defaults
Ext.applyIf(this, {
title:'Example',
header:true,

tbar: [
{ text: 'Commit' },
"-",
{

text: 'Export',
menu: {
items: [
{ xtype: 'toptoolbarexportfile' }

]
}

},
"-"
],
layout:'fit',

items: []
});
// call the superclass's initComponent implementation
app.SinglePanel.superclass.initComponent.call(this);
},
// override initEvents
initEvents: function() {
// call the superclass's initEvents implementation
app.SinglePanel.superclass.initEvents.call(this);
}

});
// register an xtype with this class
Ext.reg('singlepanel', app.SinglePanel);
app.app = function() {
return {
// public properties, e.g. strings to translate
// public methods
init: function() {

var singlePanel = new app.SinglePanel({});
singlePanel.render('panel');
}


};
}();
</script>
<script type="text/javascript">
Ext.BLANK_IMAGE_URL = '../../resources/images/default/s.gif';
Ext.onReady(app.app.init, app.app); //end onReady
</script>
</head>
<body>
<div id='panel'></div>
</body>
</html>

Animal
22 Feb 2009, 10:12 AM
Why oh why would you go to the lengths of creating a class?

Want a Button? Use a Button.

Want a Panel? Use a Panel.

josh803316
22 Feb 2009, 10:22 AM
In this case, I totally agree, it is overkill.....but still I wondered why it didn't work or what I was doing wrong?

josh803316
22 Feb 2009, 12:27 PM
Ok, I think I'm finally getting to the bottom of the issue. It has to do with the menu and using the xtype for items inside the menu.

if I do this this it works:


tbar: [
{ xtype: 'toptoolbarexportfile' }
]


But if I do this it doesn't:


tbar:
[
{

text: 'Export',
menu: {
items: [
{ text: 'dude', xtype: 'toptoolbarexportfile' }

]
}

},
"-"
]

Barius
13 Mar 2009, 2:31 PM
I have this same issue where an extended Button will not display if put inside a sub-menu, but works fine if put directly into the top level toolbar. I'm doing it slightly differently though, I am using new MyButton({..}) in the menu items rather than using an xtype.

I get the error "el.ownerDocument is undefined" after clicking on the top-level button (i.e. it happens when the sub-menu tries to init/render). So far I am totally stumped as even the most basic extended Button (that does nothing) has this behaviour. There has to be a bug somewhere (using v2.2.1) but I can't figure it out.

mjlecomte
13 Mar 2009, 2:47 PM
If you want help suggest y'all post working showcase. How to do that is explained here:
http://extjs.com/learn/Ext_Forum_Help#Posting_a_working_showcase

Barius
13 Mar 2009, 3:22 PM
The example below can be put into the base directory of an Ext 2.2.1 installation.
It is the most basic example I could think of, and it has the exact behaviour I described (at least, in Firefox 3, I don't use IE or Safari so I couldn't say what behaviour it might have there).

Observations:
- Clicking (one or more times) on the button 'Menu w/ Sub Menu' nothing happens, and no errors reported.

- Clicking on the down arrow of the 'Menu w/Sub Menu' button the first time does nothing and no errors reported.

- Clicking on the down arrow of the 'Menu w/Sub Menu' button the second time generates the error "el.ownerDocument is undefined", and results in a small empty menu 'stub' appearing below the button.

- Clicking on the down arrow key subsequent times result in nothing.

To me it looks like a problem in the code of the click event on the MenuButton object that is supposed to call the init/render of the sub menu. Of course, what do I know?



<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
<title id='title'>Title</title>

<!-- ** CSS ** -->
<!-- base library -->
<link rel="stylesheet" type="text/css" href="resources/css/ext-all.css" />

<!-- overrides to base library -->


<!-- ** Javascript ** -->
<!-- base library -->
<script type="text/javascript" src="adapter/ext/ext-base.js"></script>
<script type="text/javascript" src="ext-all-debug.js"></script>


<!-- overrides to base library -->

<!-- extensions -->

<!-- page specific -->

<script type="text/javascript">
Ext.BLANK_IMAGE_URL = 'resources/images/default/s.gif';

Ext.onReady(function(){
Ext.QuickTips.init();

Ext.ux.MyButton = Ext.extend(Ext.Toolbar.Button, {}); //most basic extension possible!!

var tb = new Ext.Toolbar();
tb.render('toolbar');

tb.add(
new Ext.Toolbar.MenuButton({
text: 'Button w/ Sub Menu',
menu : { items:[ new Ext.ux.MyButton({text:'MyButton!!'}) ] }
})
);
});

</script>

</head>
<body>
<div id="container">
<div id="toolbar"></div>
</div>
</body>
</html>

Barius
13 Mar 2009, 4:25 PM
A little further investigation reveals:

- The error 'el.ownerDocument is undefined' is being generated in ext-all-debug.js
in DomHelper.insertHTML() at "var range = el.ownerDocument.createRange();" (approx. line 247).

- The element that fails is the sub-menu, not the extended button as I had expected:



tb.add(new Ext.Toolbar.MenuButton({id:'TOPMENU',
text: 'Button w/ Sub Menu',
menu : {
id:'SUBMENU', //<--- THIS IS THE PROBLEM ELEMENT THAT HAS NO ownerDocument PROPERTY
items:[ new Ext.ux.MyButton({text:'MyButton!!'}) ]
}
})

mjlecomte
13 Mar 2009, 6:33 PM
Doing a little debugging it appears that your problem is of misuse, not any bugs in the code.

You can do a simple check, just don't even specify an extension. Just specify the standard toolbar button and run it and you'll get the same error.

Set a breakpoint where you do add and do some debugging and see why you're mis-using.

I suspect your problem area is when you hit:


var b = config;
if(!(config instanceof T.Button)){
b = config.split ?
new T.SplitButton(config) :
new T.Button(config);
}


If you really need to have that extended class for who knows what reason, suggest maybe looking at addItem.

What all are you doing that extending is required?

Animal
14 Mar 2009, 8:36 AM
Right now, menus can only contain MenuItems.

If you look at the docs carefully, you see that Menu does not extend Container.

Barius
14 Mar 2009, 11:02 AM
You truly live and breathe Ext Animal, lol. Thanks.

@mjlecomte

As with anything being extended the purpose is to share a common function with many pages. What I have is an Inventory widget which is a prototyped object that encapsulates a View (Window/tabs/grids) and the various Stores and vars needed to use it. The widget itself is rather 'heavy' and so it was designed to be included/instantiated only once in a page. This means that using it multiple times in a page requires it to be re-configured before each use. The purpose of extending a button was so that the button could be instantiated multiple times with different config values (urls for the stores, titles for the window/grids, etc). I.e. the button is an encapsulation of the config and control of the Inventory widget.

I'll try extending a MenuItem instead and see where that gets me. The downside to this is that a MenuItem shouldn't be used outside a menu, but there could be cases where I'd want to open the Inventory widget from a non-menu (a Form button for example).

I was looking at Actions as well, but I'm not sure that's the right approach.

If you have a better idea let me know.

Animal
14 Mar 2009, 11:18 AM
In Ext 2.*, you will have to wrap any Component that you wish to place in a Menu in a http://extjs.com/deploy/dev/docs/?class=Ext.menu.Adapter

In Ext 3.0, a Menu is a Container.

Barius
14 Mar 2009, 1:22 PM
Hmm, that's a pretty cool trick. I'm learning so much today!

Unfortunately, the adapted button in the sub-menu is literally a 'button' and doesn't look like a menu item.

I suppose I'll have to create two versions, one for menus and one for regular containers/forms/etc.

Animal
15 Mar 2009, 2:33 AM
Mm. yes, a Button will look like a Button.

What is it that you want if you are asking for a Button?