PDA

View Full Version : Can't get reference to my menu?



Maxeta
19 Nov 2013, 7:34 AM
I'm using MVC, and am having a bit of trouble getting a reference to a menu item of a button item of a toolbar:

1. 'menu[itemId=Startmenu]'
2. 'Taskmenu menu[itemId=Startmenu]'
3. 'Taskmenu button[itemId=Startbutton] menu[itemId=Startmenu]'

#1 Works, #2 & #3 do not... not entirely sure why? I though I was looking for a menu named Starmenu of a button named Startbutton, of a component with xtype Taskmenu. Am I just not using the selectors properly?

Here is my code:

VIEW


Ext.define('appName.view.vTaskmenu', {
extend: 'Ext.toolbar.Toolbar',


alias: 'widget.vTaskmenu',
xtype: 'Taskmenu',


border: false,


items: [
{
xtype: 'button',
text: 'Main Menu',
itemId: 'Startbutton',
cls: 'x-btn-default-small-over'
}
],


initComponent: function () {
var me = this;
me.callParent();
clog('vTaskmenu.initComponent()');
}


});


CONTROLLER


Ext.define('appName.controller.cTaskmenu', {
extend: 'Ext.app.Controller',
views: ['vTaskmenu'],


init: function () {
var me = this;
me.control({
'Taskmenu button[itemId=Startbutton]': {
added: me.setMenu
},
'Taskmenu button[itemId=Startbutton] menu[itemId=Startmenu]': {
click: me.useMenu
}
});
clog('cTaskmenu.init()');
},


setMenu: function (me, container, pos, eOpts) {
me.menu = Ext.create('Ext.menu.Menu', {
itemId: 'Startmenu',
margin: '0 0 10 0'
});
var x = Ext.getStore('sIcons');
x.load({
callback: function (records, operation, success) {
for (var i = 0; i < records.length; i++) {
me.menu.add({
text: records[i].get('Title')
});
}
}
});
},


useMenu: function (me, item, e, eOpts) {
alert(item.text);
}


});

tvanzoelen
19 Nov 2013, 9:06 AM
What if you reference on the alias vTaskmenu?

Maxeta
19 Nov 2013, 9:10 AM
That doesn't work either.

tvanzoelen
19 Nov 2013, 11:30 AM
Sticking to your code, the thing below is working for me. I only changed the added event to render. Added is not firing. Then I suggest to use xtype or alias - not both.



Ext.define('Testing.view.vTaskmenu', {
extend: 'Ext.toolbar.Toolbar',

alias: 'widget.vTaskmenu',
xtype: 'Taskmenu',

border: false,

items: [
{
xtype: 'button',
text: 'Main Menu',
itemId: 'Startbutton',
cls: 'x-btn-default-small-over',
menu: Ext.create('Ext.menu.Menu', {
itemId: 'Startmenu',
margin: '0 0 10 0'
})
}
],


initComponent: function () {
var me = this;
me.callParent();
console.log('vTaskmenu.initComponent()');
}

});


Controller



Ext.define('Testing.controller.cTaskmenu', {
extend: 'Ext.app.Controller',
views: ['vTaskmenu'],
refs: [{
ref: 'taskMenu',
selector: 'Taskmenu button[itemId=Startbutton]'
}],

init: function () {
var me = this;
me.control({
'Taskmenu button[itemId=Startbutton]': {
render: me.setMenu
},
'Taskmenu button[itemId=Startbutton] menu[itemId=Startmenu]': {
click: me.useMenu
}
});
console.log('cTaskmenu.init()');
},

setMenu: function (me) {

var b = this.getTaskMenu();

b.menu.add(
{text: 'Menu Item 1'}
);

console.log('setmenu');

},


useMenu: function (me, item, e, eOpts) {
console.log('usemenu');
}


});

Maxeta
19 Nov 2013, 11:52 AM
Hmmm... okay so based on your changes, I just moved the dynamic menu creation, inline into the view, and left the menu item creation in the controller (but left it bound to the added event). This seems to make everything work as expected. So what I'd like to know, is what if anything was I missing from the dynamic menu creation? Possibly a renderTo? It's pretty apparent the menu was not being created as a child of the button (and now it definitely is). Checkout my code below:

VIEW:


Ext.define('appName.view.vTaskmenu', {
extend: 'Ext.toolbar.Toolbar',

alias: 'widget.vTaskmenu',
xtype: 'Taskmenu',

border: false,

items: [
{
xtype: 'button',
text: 'Main Menu',
itemId: 'Startbutton',
cls: 'x-btn-default-small-over',
menu: Ext.create('Ext.menu.Menu', {
itemId: 'Startmenu',
margin: '0 0 10 0'
})
}
],

initComponent: function () {
var me = this;
me.callParent();
clog('vTaskmenu.initComponent()');
}

});


CONTROLLER


Ext.define('appName.controller.cTaskmenu', {
extend: 'Ext.app.Controller',
views: ['vTaskmenu'],

init: function () {
var me = this;
me.control({
'Taskmenu button[itemId=Startbutton]': {
added: me.setMenu
},
'Taskmenu button[itemId=Startbutton] menu[itemId=Startmenu]': {
click: me.useMenu
}
});
clog('cTaskmenu.init()');
},

setMenu: function (me, container, pos, eOpts) {
var x = Ext.getStore('sIcons');
x.load({
callback: function (records, operation, success) {
for (var i = 0; i < records.length; i++) {
me.menu.add({
text: records[i].get('Title')
});
}
}
});
},

useMenu: function (me, item, e, eOpts) {
alert(item.text);
}

});

tvanzoelen
19 Nov 2013, 12:07 PM
The menu property is empty / undefined if you do not set it at render time on the button. So I suggest just to create an empty menu and add the items when you have them at hand. Probably there are ways as well to add or create the menu dynamically, in that case you probably have to re-render the button. I think in that case it is easier to just recreate the button.

Maxeta
20 Nov 2013, 6:33 AM
So when I use:



me.menu = Ext.create('Ext.menu.Menu', {
itemId: 'Startmenu',
margin: '0 0 10 0'
});


the menu isn't rendered to the button (even though me = my button)? I mean the menu is definitely getting rendered because I can access the click events via 'menu[itemId=Startmenu]', but it's just not rendered to the button? Which is why 'Taskmenu button[itemId=Startbutton] menu[itemId=Startmenu]' doesn't work (well unless it was added as part of the view, then it does work)?

I'm just trying to figure out and understand how dynamic generation of components works, because I'm going to have a lot of it in my application, and right now, I'm still a little confused. I mean if I put an alert(me.menu.up('button').id) into the menu generation piece, and have the menu as part of the view, I get the button id. But if I dynamically generate my menu as shown above, I get undefined. So how do I know where it's actually getting placed in the DOM?

tvanzoelen
20 Nov 2013, 8:25 AM
Menu is a config property of the Button class. So the menu is added when constructing the button.
See here a piece of code coming out of the initComponent of the button class


if (me.menu) {
// Flag that we'll have a splitCls
me.split = true;

// retrieve menu by id or instantiate instance if needed
me.menu = Ext.menu.Manager.get(me.menu);

// Use ownerButton as the upward link. Menus *must have no ownerCt* - they are global floaters.
// Upward navigation is done using the up() method.
me.menu.ownerButton = me;
}


Its seems that buttons are general floaters :) Normally if you add components dynamically you use the add function which is member of the AbstractContainer. Because the Button doesn't inherent from the Abstract Container you do not have such function for the button.

You could try to see what happens if you set the ownerButton property of the menu.It could be you have to re-apply the renderTpl of the button for setting some classes right.

But in general you use the add function to add components, setting config properties after render will in most cases not have any effect.

Maxeta
20 Nov 2013, 8:31 AM
Yes, setting ownerButton worked perfectly. Thank you. Now I have a better idea of what's going on.


UPDATE: Question

Where is ownerButton in the docs? I can't seem to find any information about it. floatParent seems to work, but the documentation on that one seeme to state the opposite (that is shouldn't work)?!?!?! Especially since it's marked as readonly... but I definitely wrote it to... so...