PDA

View Full Version : [solved] Problem accessing parent from submenu



rblon
22 Sep 2009, 6:57 AM
Hi,

I have a menu with checkitems which have submenu's. I try to get the following behaviour:


if someone selects (deselects) an item in the menu, all items in corresponding submenu get selected (deselected)
if someone deselects an item in a submenu, the corresponding menu item gets deselected

1) works, but 2) not, as I am not able to access the parent menu item. I have tried all kinds of methods (ownerCt, findParentByType, scope) but no luck so far.

I'm hoping a more experienced (Ext)JS coder can easily point out my mistake.



Ext.onReady(function() {

function menuHandler(item, checked) {
// Check / uncheck all items in subMenu
var subMenu = item.menu;
for (var i = 0; i < subMenu.items.length; i++) {
var item = subMenu.items.get(i);
item.setChecked(checked, true);
}
}

function subMenuHandler(item, checked) {
// Uncheck parent menu
if (!checked) {
var parent = item.findParentByType('menucheckitem');
parent.setChecked(false, true);
}
}

var menu = new Ext.menu.Menu({
defaults: {
checked: false,
checkHandler: menuHandler,
hideOnClick: false
},
items: [{
text: 'Item 1',
checked: false,
menu: {
defaults: {
checked: false,
checkHandler: subMenuHandler,
hideOnClick: false
},
items: [{
text: 'Item 1.1',
}, {
text: 'Item 1.2',
}]
}
}, {
text: 'Item 2',
checked: false,
menu: {
defaults: {
checked: false,
checkHandler: subMenuHandler,
hideOnClick: false
},
items: [{
text: 'Item 2.1',
}, {
text: 'Item 2.2',
}]
}
}]
});

new Ext.Button({
text: 'Menu',
renderTo: 'btn',
menu: menu
});

});

rblon
24 Sep 2009, 12:01 AM
Sorry to reply to my own post, but I would like to ask once more for your attention as it moved to page 7 without a reply.

I am trying in the checkhandler to access the menucheckitem one level above. Is that possible?

Animal
24 Sep 2009, 2:04 AM
Should work. What have you done to debug before trying the last resort of posting here?

rblon
24 Sep 2009, 2:35 AM
I run into this problem in a larger application, and created this example to showcase the issue.

The code as it is now gives the error: "parent is null"

So I have tried following alternatives (where the last 3 probably "show off" my ExtJS lack of understanding):

var parent = item.findParentByType('menuitem'); // "parent is null" error
var parent = item.parentMenu; // "parent.setChecked is not a function" error
var parent = item.ownerCt; // "parent.setChecked is not a function" error
var parent = item.ownerCt.ownerCt; // "parent is undefined" error

Animal
24 Sep 2009, 2:38 AM
Yes, but what debugging have you done?

rblon
24 Sep 2009, 3:07 AM
The "parent is null" error doesn't give me a lot of opportunity to do any debugging.
With alternative 2) and 3) i have put in a
alert(parent.items.length);
statement which shows me the parent is pointing to the menu object (i have added a third item to the second menu, so I get either to '2' or '3').
My question is how to go from there to the menucheckitem which property this 'menu' is. Things like
var parent = item.parentMenu.ownerCt; // equivalent to item.ownerCt.ownerCt;
var parent = item.parentMenu.findParentByType('menucheckitem');
give "parent is undefined" or "parent is null" error.

aconran
25 Sep 2009, 2:18 PM
This feels a lot more difficult than it should be. Look for a fix for this in an upcoming release.

To access the item which the new menu has expanded from you'll need to use the following:


var activeItem = item.parentMenu.parentMenu.activeItem;


You can use this code inside your subMenuHandler function and then invoke the setChecked method of the MenuItem.

Explaination:
- item has a reference to it's parentMenu (which is the menu its contained within)
- this menu has a reference to its parentMenu which it was opened from
- activeItem is the active menu item for any particular menu

rblon
26 Sep 2009, 11:52 AM
Thanks vm aconran. Basically I have replaced the red line in my code with your suggestion



var parent = item.parentMenu.parentMenu.activeItem;
and it works as intended.

I have to say that the API documentation is not very clear that the activeItem property can be used for this purpose, as it says:

activeItem (http://www.extjs.com/forum/../deploy/dev/docs/source/Container.html#cfg-Ext.Container-activeItem) : String/NumberA string component id or the numeric index of the component that should be initially activated within the container's layout on render. For example, activeItem: 'item-1' or activeItem: 0 (index 0 = the first item in the container's collection)

Btw, what kind of fix do you have in mind? If the documentation for activeItem property is somewhat changed, I think it should be fine.



This feels a lot more difficult than it should be. Look for a fix for this in an upcoming release.

mjaomaha
28 Sep 2009, 8:22 AM
I ran into this issue as well. My solution is that you have access to the menu parent while you are creating the child, so I make a new custom attribute on the child as I create it, which is a reference to the parent. I didn't check the syntax, but something like this... without my code, I can only give you the general idea, but you can experiment by using firebug when the appropriate time to make a reference to "this" in the child would be.


Ext.onReady(function() {
....

function subMenuHandler(item, checked) {
// Uncheck parent menu
if (!checked) {
var parent = item.findParentByType('menucheckitem');
var parent = item.parentItem;
var parentOfParent = item.parentItem.parentItem;
parent.setChecked(false, true);
}
}

var menu = new Ext.menu.Menu({
defaults: {
checked: false,
checkHandler: menuHandler,
hideOnClick: false
},
items: [{
parentItem : this,
text: 'Item 1',
checked: false,
menu: {
defaults: {
checked: false,
checkHandler: subMenuHandler,
hideOnClick: false
},
items: [{
parentItem : this,
text: 'Item 1.1',
}, {
parentItem : this,
text: 'Item 1.2',
}]
}
}, {
parentItem : this,
text: 'Item 2',
checked: false,
menu: {
defaults: {
checked: false,
checkHandler: subMenuHandler,
hideOnClick: false
},
items: [{
parentItem : this,
text: 'Item 2.1',
}, {
parentItem : this,
text: 'Item 2.2',
}]
}
}]
});

mjaomaha
28 Sep 2009, 8:37 AM
Also as a javascript developer, I would not know what to do if I was not using firefox WITH firebug installed. You can put break points in your javascript, and inspect every attribute and method available at each step of the code. It is actually amazing, because I used to debug with "alert()" and it was like using a rock instead of a hammer and screwdriver ;).

rblon
28 Sep 2009, 10:42 AM
Hi mjaomaha,

I have to admit I don't understand your suggestion. The problem, as I see it, is that I have to move up to the top "items" container, and then have to decide which (main-menu) item I need, based on the sub-menu where an item has been deselected. As aconran explained, the activeItem property can be used for this purpose.

It seems that you approach it as a scope issue, which I don't think is the case (when I made my initial post, I did think that might be a problem).

I might be misinterpreting, though. However, the code doesn't work. Also after trying a few variations, like



if (!checked) {
var parent = item.parentItem.parentItem;
parent.setChecked(false, true);
}