PDA

View Full Version : Ext.ux.menu.StoreMenu - Ajax Store as menu-item config



wm003
3 Mar 2009, 6:25 AM
Just a little widget to be able to create menus with stores as item-config:

Demopage: http://www.lubber.de/extjs/storemenu

Current Version v 0.2

Revision History
v 0.2 [2009/03/04]
- added support for submenu ("menu" has to be delivered such as "handler")

v 0.1 [2009/03/03]
Initial release


Simple call:


var menu = new Ext.ux.menu.StoreMenu({
url:'gimme_json_menu_entries.php',
baseParams: {
var_one: 'foo',
var_two: 'bar'
}
});
StoreMenu will show a loading indicator when the menu is opened the first time and renders the final menu after ajax-response.

it would process a returned json like:


[
{
"text": "first entry",
"iconCls": "iconclass1",
"handler": "function(item) {alert('entry one is called '+item.text);}"
},
'-',
'some text',
'-',
{
"text": "entry 2",
"iconCls": "iconclass2",
"handler": "function(item) {myextapp.my_public_method(1234,'abc');}"
},
{
"text": "submenu",
"iconCls": "iconclass3",
"menu": "new Ext.ux.menu.StoreMenu({url:'menu_entries.php'})"
}
]Note, handler or menu-functions are delivered as string! StoreMenu takes care and creates real functions out of them.

mrsunshine
3 Mar 2009, 11:33 AM
Cool, do you have a running demo?

wm003
4 Mar 2009, 4:21 AM
Cool, do you have a running demo?

yep(as of now, it was a question of time until somebody asks for a demopage);)
http://www.lubber.de/extjs/storemenu

incaic
18 Mar 2009, 11:51 AM
Nice extension wm003!

I tried it out, but am having some issues.

My server returned JSON is:



{
status: true,
data: [{
'first'
,'-'
,'second'
}]
}


I need to dynamically add a menu above StoreMenu, so have:



m.menu.add({
menu:new Ext.ux.menu.StoreMenu({
url:this.url
,baseParams:{method:'getMenu'}
})
})


I get the loading swirl, but then once call is complete the menu
doesn't get populated. I get an empty submenu.

I believe my problem is due to the extra "status:true" in the JSON returned
from the server. I tried adding a "reader:this.reader" to your config code for
SimpleStore, but it didn't work. The resulting code was:



var menuRecord = new Ext.data.Record.create([
{name:'config', mapping:'data'} // EDIT: I use 'config' because I saw that your code used 'config' as a field.
]);

var menuReader = new Ext.data.JsonReader({
successProperty:'status'
,root:'data'
},menuRecord);

m.menu.add({
menu:new Ext.ux.menu.StoreMenu({
url:this.url
,baseParams:{method:'getMenu'}
,reader:menuReader
})
})


Any advice?

Thanks.

incaic
18 Mar 2009, 1:17 PM
ok, after closer inspection ...

I found a simpler solution for myself, but had to alter wm003's code a bit.

I changed the type of store from SimpleStore to JsonStore and
added a root config as follows:
(I swapped this for lines 46-52)



this.store = new Ext.data.JsonStore({ // <- using JsonStore
fields:['config'],
url:this.url,
baseParams:this.baseParams,
root:this.root || 'data' // <- need to set appropriate root
});


This code works for servers that return JSON in the following format:



{
status: true,
data: [
{
"text" : "First Entry"
,"iconCls" : "iconclass1"
,"handler" : "function(item) {alert('entry one is called '+item.text);}"
}
,'-'
{
"text" : "submenu"
,"iconCls" : "iconclass2"
,"menu" : "new Ext.ux.menu.StoreMenu({url:'...',baseParams:{...}})"
}
]
}


This works for me, hope it helps someone else.

baboog
19 Mar 2009, 4:40 AM
Hello , This is my first post (so sorry if i mess up)
Nice extension btw..
My question is on the demo how are u forcing "Force Reload of all menus on each access"???
and can this be done for TreeLoader as well :) ??
Thanks
Baboog

incaic
19 Mar 2009, 8:44 AM
StoreMenu uses this listener to force the reload:



listeners:{
'beforeshow':function(){this.loaded=false;}
}

wm003
19 Mar 2009, 10:02 AM
can this be done for TreeLoader as well :) ??


just use the reload-method of the desired node of the tree.

baboog
19 Mar 2009, 10:19 PM
Thanks both of u for replying, really appreciate it

nofearnoreaper
20 Mar 2009, 8:20 AM
Hi, thanks for this menu, it's got me closer to actually finishing a project with EXTJS than anything else. I'd been banging my head against the issue of a dynamically loaded menu for far too long.

If you see the code below:


var dynmen = new Ext.ux.menu.StoreMenu({

url:'json_user_menu.asp' (http://extjs.com/forum/'json_user_menu.asp'),
baseParams: {
userTXT: userValue,
mailTXT : emailValue
},
listeners: {
beforeshow: function()
{

this.loaded=false;
}
}

})

I would have assumed that the store would reload every time you select the menu item? So as I pass a different BaseParam to the store the menu is populated with hrefs that use the new BaseParam as part of the querystring:



[{"text": "Player Search","iconCls": "iconclass1", "href":"inputString.asp?key=test1234", "hrefTarget":"_blank"},{"text": "Blue Page","iconCls": "iconclass1", "href":"cgi-bin/admin.exe?type=test1234\&player=", "hrefTarget":"_blank"},{"text": "White Page","iconCls": "iconclass1", "href":"user.asp?user=test1234", "hrefTarget":"_blank"},{"text": "Current Player Status","iconCls": "iconclass1", "href":"user_tables.asp?player=test1234", "hrefTarget":"_blank"},{"text": "Credit Status","iconCls": "iconclass1", "href":"user_credit.asp?player=test1234", "hrefTarget":"_blank"},{"text": "Real Money Transfers","iconCls": "iconclass1", "href":"user_transfers.asp?switch=Real\&player=test1234", "hrefTarget":"_blank"}]


You see from the code above the userID passed is 'test1234' . the user ID is passed from a successful query on the database which is parameterised by a form field where the userID can be input. I want to reload the staor every time a new search is performed on the database returning a new userID, so changing the querystring of the hrefs in the store menu. What is the best way to achieve this, any help would be greatly appreciated.

Thanks

wm003
20 Mar 2009, 10:01 AM
You should change the baseparams and set the loadingstate to false just after the user value has been changed


var msm = Ext.getCmp('myStoreMenu');
msm.baseParams = {userTXT: userValue, mailTXT : emailValue};
msm.loaded=false;

the next time the menu is shown it will be forced to reload the itemconfig.

baboog
24 Mar 2009, 3:58 AM
hey guys,
sorry its a noob question :) but, please need help,
i have one 'StoreMenu' defined
i wanted to use that menu for multiple items of a TOOLBAR (rather than a new StoreMenu for each )and in baseParams send the id or text of the toolbar item clicked. and using that param in server side to decide what MENU to send .. any way how i can get the id/text of clicked toolbar item in baseParams :) ???
thanks
baboog

luisparada
24 May 2009, 1:19 PM
I'm trying to do the same thing, but i need to dynamically load the entire items of the toolbar even the root ones, this is my code:


init : function(){
this.initRecordDef();
var records = this.getRecordDef();
var storeMenu = new Ext.data.JsonStore({
proxy:new Ext.data.HttpProxy({url:'modules.php'+'?action=getMenu&response=menu&mname=menu'}),
fields:[records],
root:'rows'
});

var mainMenu = new Ext.ux.menu.StoreMenu({
store:storeMenu,
listeners:{
'beforeshow':function(){
console.log(this.store)
this.loaded=false;
}
}
});

var panel = new Ext.Panel({
header:false,
width:896,
autoHeight:true,
tbar: new Ext.Toolbar([{
text:'StoreMenu 1(normal menu entries)',
menu:mainMenu
}]),
renderTo: Ext.getDom('titulo-tools')
});
}
});

I mean how can I load all items from jsonStore using storemenu as the root of the toolbar ?
something like this:


var panel = new Ext.Panel({
header:false,
width:896,
autoHeight:true,
tbar: new Ext.Toolbar([///mainMenu using storeMenu////]),
renderTo: Ext.getDom('titulo-tools')
});

wm003
26 May 2009, 1:23 AM
StoreMenu is a special Menu-Item with ajax-load-store functionality. it cannot be used as a toolbar. You need to create a similiar toolbar-UX like i did with the Menu-function.

Sesshomurai
30 Jun 2009, 7:01 AM
Hi,
I'm trying to use this with Ext3. Pretty much works except one minor visual glitch. When mousing over the menu item, whose submenu is a StoreMenu, the submenu doesn't show correctly, but if I mouse away and then back, I get the "Loading" and then the items show properly. After that, its ok.

Is there some css/style tweak needed for Ext3? Thought I'd ask before I start tweaking..

wm003
30 Jun 2009, 11:42 PM
Hi,
I'm trying to use this with Ext3. Pretty much works except one minor visual glitch. When mousing over the menu item, whose submenu is a StoreMenu, the submenu doesn't show correctly, but if I mouse away and then back, I get the "Loading" and then the items show properly. After that, its ok.

Is there some css/style tweak needed for Ext3? Thought I'd ask before I start tweaking..
:-? i cannot reproduce this with Ext 3.0-RC2 (using my demopage). Could you provide some testsite where this occurs?

ibradley
3 Aug 2009, 8:37 AM
Hi there. Have been using this excellent extension for a while, but come across a small issue with it.
I'm using it as a dynamic context menu in a Ext grid and Ext Tree. When the menu (or a storemenu sub-menu) is loaded for the first time and the XY coordinates clicked are near the bottom or right of the viewport/screen the menu gets cropped (see screenshot).
If you click-out of the menu/submenu and then reload it the menu is then positioned correctly within the bounds of the viewport/screen. This happens whether the menu is set to auto-reload or not.
I'm guessing that Ext is trying to reposition the menu before it is fully loaded or something like that.
Any ideas?

iceblast_01
16 Aug 2009, 11:41 PM
hi i looked at the sample, everytime i click or mouse over the menu it always loads, is there a way to load the menus upon loading the panel, and not loading it again? like loading it once and thats it

-edit: ok nvrmind i made it to load only once, what i want to do now is to have something like this for the whole toolbar, with menus and submenu and do it on a single request, what i mean is here it ask for new json for each menu, is it posible to create several menu in a single json string?

wm003
17 Aug 2009, 11:55 AM
Sure, you just need to code something similar to storemenu for the toolbar. Take a look at post #14 of this thread.

hallikpapa
23 Aug 2009, 6:16 PM
Like this plugin.

If I return a list of 10 checkboxes, I would like to submit all the unchecked checkboxes to the server. So far I just have it doing it one at a time. It only sees the most recent unchecked box. Ideas on what I should do?

Here's what php is sending back in my handler, and it works, but there's got to be a cleaner way.



$data[$i]['handler'] = "function(item) { var sp = Ext.getCmp('test-aaa').menu.items; var array = new Array();
for(i in sp.items) {
if(sp.items[i].checked == false) {
array.push(sp.items[i].id); } }
array.push(item.id);
Ext.getCmp('service-provider-column-chart').store.load( {params:{id: Ext.encode(array)}}) } ";

ajatib
24 Aug 2009, 7:25 AM
Hi there. Have been using this excellent extension for a while, but come across a small issue with it.
I'm using it as a dynamic context menu in a Ext grid and Ext Tree. When the menu (or a storemenu sub-menu) is loaded for the first time and the XY coordinates clicked are near the bottom or right of the viewport/screen the menu gets cropped (see screenshot).
If you click-out of the menu/submenu and then reload it the menu is then positioned correctly within the bounds of the viewport/screen. This happens whether the menu is set to auto-reload or not.
I'm guessing that Ext is trying to reposition the menu before it is fully loaded or something like that.
Any ideas?

Im a little curious... Whats that application u show in the image?.

ibradley
24 Aug 2009, 8:21 AM
Im a little curious... Whats that application u show in the image?.

It's a content management system that we developed using ExtJS. See http://www.ibcomputing.co.uk/588/content-management-systems/ for further info.

yuer2084
25 Aug 2009, 6:40 PM
I know that the handler should be a public function,how can i access a private one.
it's commonly that the menu used in a window,and i hope the handler could access the window's private function,how can i do it?

nofearnoreaper
8 Sep 2009, 2:24 AM
Hi, I was wondering if it's possible to load the simplestore that populates the drop-down menu prior to the toolbar button being clicked?

An example would be a search button, separate to the toolobar being clicked and a user being found. The action of a user being found to start the loading of the simplestore, so that when a toolbar button is selected the load time of the related drop-down menu is reduced.

The current issue I have is that : A new search puts a new record from the database in context, the menu then takes about 3-4 seconds to load again once a user clicks on the related toolbar button. I'd like to ideally reduce the load time by loading the simpleStore populating the menu in the background as soon as a new user is searched for.

Hopefully that makes some sense.

Thanks

wm003
8 Sep 2009, 12:16 PM
Hi, I was wondering if it's possible to load the simplestore that populates the drop-down menu prior to the toolbar button being clicked?


try something like this (untested...)


mystoremenu.store.reload()

slyons
6 Jan 2010, 11:00 AM
Very nice plugin wm003!

Just thought I would make note for anyone utilizing a reader to interpret the returned json like I am (I'm using Cutters CFQueryReader (http://www.extjs.com/forum/showthread.php?t=76071)), you can modify the StoreMenu addon to accept your reader like so:



this.store = new Ext.data.Store({ <-change to a store appropriate to your reader
fields: ['config'],
reader: this.reader, <-add reader config option
url: this.url,
baseParams: this.baseParams
});


which would allow you to pass the reader with the config options like so:



var myMenuStore = new Ext.ux.menu.StoreMenu({
reader: myReader,
url:'/path/to/proxy.cfc' (http://www.extjs.com/forum/'/path/to/proxy.cfc'),
baseParams: {
method:'getData',
returnFormat:'JSON'
}
});


This is probably trivial knowledge to the more experienced but as a newbie it took me a while to figure it out so I thought I would share.

yytong
22 Jan 2010, 11:32 AM
Hi,

I have json file like following:

{
"success": true,
"PersonData":{
"count": 9,
"Data":[
{
"pId":1,
"lname":"Barry",
"mname":"C",
"fname":"Barbera"
},{
"pId":2,
"lname":"Duck",
"mname":"DD",
"fname":"Donald"
},
.....
]
}
}

I want to show the menum with my template like following:

var personTpl=new Ext.XTemplate(
'<tpl for="."><div class="pt-item">',
'<span class="gridTitle">{fname} {mname} {lname}</span>',
'</div></tpl>'
);

I would like to have a menu with the json data and show it in the template I provide.

Currently, seems the storemenu takes one field from the json file only, how can I app template to it? Did anybody try it before?

Many thanks in advance! :)

Yytong

ibradley
18 Feb 2010, 7:15 AM
I finally found a way of fixing the issue I described in post no. 17. I thought I would share my patched source code in case anyone else is struggling with this issue. Please see the attachment for a working version.

j_mmontero
9 Mar 2010, 8:40 AM
I'm trying to run the examples on 3.0 but I don't get any results.

ajax graphics is loading and not displaying anything.

Any clue?
I have a grid panel with a context menu. When I right click it opens the menu then I hover the submenu item i got the ajax graphics loading but that's it.


var messageContextMenu = new Ext.menu.Menu({
id: 'messageContextMenu',
items: [
{
text: 'submenu',
iconCls: 'icon-1',
menu: new Ext.ux.menu.StoreMenu({
url:'Menu',
baseParams:
{
menu_id: 4,
method: "getItems"

},
listeners: {
itemclick: function(item,e) {
Ext.MessageBox.alert("StoreMenu Contextmenu",item.text);
}
}
});
},
{text: 'Edit', handler: Ext.emptyFn , iconCls: 'icon-edit'}
]
});json:
[{ 'text':'first entry','iconCls': 'iconclass1','handler': 'function(item) {alert('entry one is called '+item.text);}}]

Any help will be greatly appreciated!

Titina
9 Apr 2010, 6:35 AM
Hi, I have a storeMenu with 2 levels:
First level shows some itemsX returned by a json request. Each itemX, on mouse over, shows another storeMenu with itemsY by itemX.
My problem is, the submenu showing the itemsY is only showing itemX yes, itemX no (meaning, if I have itemX1, itemX2 and itemX3, on mouse over them sequentially, itemX1 will open the submenu, then itemX2 won't, and itemX3 will - that only happen if I mouse over them fast - if I go slowly, they all show OK).
I couldn't find a solution for this problem in this forum (sry, I'm a noob here). Anyone knows how to solve this? I would be really grateful!

wm003
11 Apr 2010, 8:47 PM
@Titina: Could you please provide some of your sample code? (and the json from the requests). i guess there is soemthing wrong in the definition of the menu-structure basically. Does it work, if you do _not_ use storemenu, but the usual menu?

wm003
11 Apr 2010, 8:52 PM
json:
[{ 'text':'first entry','iconCls': 'iconclass1','handler': 'function(item) {alert('entry one is called '+item.text);}}]


you have used single quotes twice: To wrap the handler function and within this function, which will get a javascript syntax error:
And you forgot the last quote, so this has to crash :)
try this instead:


[{ 'text':'first entry','iconCls': 'iconclass1','handler': "function(item) {alert('entry one is called '+item.text);}"}]

Titina
12 Apr 2010, 9:15 AM
The idea is to use the menus to choose the filters to be applied to a grid. The main menu applies one filter, the combo menu + submenu applies another filter.

The code is as follows:


mainMenu= new Ext.ux.menu.StoreMenu({
url:'py_menu_items',
baseParams: {
table: 'section',
column1: 'section_id',
column1: 'section_name',
submenu: 'subMenu',
hasSon: 1
},
listeners: {
mouseover: function(t,e,menuItem){
gridStore.baseParams['section'] = menuItem.getId();
gridStore.baseParams['type'] = "";
},
click: function()
{indicador.setText(gridStore.baseParams['section']); }
}
}); SubMenu code:


subMenu= new Ext.ux.menu.StoreMenu({
url:'py_menu_items',
id: 'type_name',
baseParams: {
table: 'type',
column1: 'type_id',
column2: 'type_name',
submenu: 'none',
hasSon: 0
},
listeners: {
mouseover: function(t,e,menuItem){
gridStore.baseParams['type'] = menuItem.getId();
},
click: function()
{indicador.setText(gridStore.baseParams['section'] + '/' + gridStore.baseParams['type']);
}
}
});

The mouseover listener sets the filters to be used on the grid (section id if clicked is on the mainMenu, or section id + type id if the click event is on the subMenu). The click function then loads the grid with the filters.

The JSON response is:



[{"text": " section1" , "id": "section1" , "handler": "function(){gridStore.baseParams['activeFilter'] = '1';}" , "menu": " subMenu" },
{"text": " section2" , "id": "section2" , "handler": "function(){gridStore.baseParams['activeFilter'] = '1';}" , "menu": " subMenu" },
{"text": " section3" , "id": "section3" , "handler": "function(){gridStore.baseParams['activeFilter'] = '1';}" , "menu": " subMenu" }]


The problem is, I have like 3 sections in the database, and the first subMenu is loaded ok on mouse over the first menu item. But right after I mouse over the second menu item, its subMenu isn't loaded, and then, over the third, the subMenu loads ok. If I mouse over then slowly, they all load, but thing is, no one will mouse over slowly.

Please, any help, idea would be extremely welcome, I have tried all sort of things and none works!

Titina
13 Apr 2010, 6:21 AM
Ok, I did some tests. I created a normal menu with all the items already there, no ajax resquests, and another empty menu, which I populate with all the items queried from the db by an ajax resquest (using the normal menu, not the storeMenu). The first menu works normally, the second one has the same problem as the storeMenu, the second submenu doesn't appear when it should. By any chance, is that a bug from ext 2.x?

wm003
13 Apr 2010, 9:25 PM
Is "subMenu" Object globally defined? When Storemenu evals the string to JS-code, the object "subMenu" must be in scope

Titina
14 Apr 2010, 4:54 AM
yes, it is globally defined...

wm003
14 Apr 2010, 5:17 AM
subMenu has a static id: 'type_name', but subMenu should be instanciated three times, so Ext will try to create 3 Objects with the same id which will result in an exception i guess. Thats, why the first menu works (because the id "type_name" was not defined yet) but all following subMenu fail to get rendered (because the id "type_name" already exists)
Try to delete the line

id: 'type_name', and see if it works now

Titina
14 Apr 2010, 5:54 AM
no, it's only the immediate following subMenu that fails to render, the third works fine.
If I changed the order of the items where the mouse passes over, for example, I first pass over the second item, then go to the first one. The second item will render fine, the first no. If I go first over the first item, and then proceed to the second item and right after to the third item, the first and the third will render ok, the second no...

I deleted the id line, and it didn't work... one thing that I tried and kinda "worked", was to insert a mouseout listener with subMenu.hide(). The menu then worked, showing all the subMenus when they should. But then, I couldn't access the subMenus, 'cuz they would hide when I mouse out the main menu... it was a dumb idea, but maybe this will be any help to see where the problem is?

saprot
18 Apr 2010, 8:55 AM
did you think of commercial license for StoreMenu, just like with your another great extension - DatePickerPlus?

wm003
18 Apr 2010, 8:26 PM
did you think of commercial license for StoreMenu, just like with your another great extension - DatePickerPlus?i will upgrade all demopages of my current and upcoming widges with options for commercial licenses soon.

Andrew Peacock
9 Jun 2010, 3:37 PM
Hi,
I'm using Ext.Direct for my DB calls, as in


var storeAccounts = new Ext.data.DirectStore({
storeId:'storeAccounts',

// Loading configuration
autoLoad: true,
directFn: Ext.PromotionBot.Accounts.getAccounts,

Is there anyway to use directFN with this great little menu of yours?

Regards,
Andy

wm003
9 Jun 2010, 9:36 PM
StoreMenu supports an own store as config item, so you might try something like



var menu = new Ext.ux.menu.StoreMenu({
store: storeAccounts
});

shawnb457
15 Dec 2010, 1:35 PM
Can you add your menu to a splitbutton.

xtype: 'splitbutton',
text: 'Group',
id: 'groupButton',
menu:buttonmenu,

var buttonmenu = new Ext.ux.menu.StoreMenu({
store:mainStore,
});
var mainStore = new Ext.data.Store({


// explicitly create reader
reader: new Ext.data.JsonReader({
idProperty: 'groupid',
root: 'groups',
fields: [
{name: 'label'},
{name: 'test'},

]
})
});

c.barca
3 Mar 2011, 2:29 AM
Hello,
I try to set some icon class on Store menu json as is:


{
"text": "normal menu line",
"iconcls": "exclamation",
"handler": "function(item) {Ext.MessageBox.alert('Ext.ux.menu.StoreMenu','You selected '+item.text);}"
},


where exclamation class is defined on external css as is :


...
.exclamation { background-image: url(../icons/exclamation.png) !important; }
...


The image was present on correct path and css file is linked on my html test page.
Any suggestion ?

Thank you, regards

wm003
3 Mar 2011, 6:47 AM
Try "iconCls" instead of "iconcls" it's case sensitive

Joe Kuan
11 Apr 2011, 1:55 AM
Hi all,

I have modified the original version StoreMenu and added several new features. As I need them in my project.

- Able to define handler from the client side
- Added function and modified StoreMenu can be used to display both menu items from Store and other components
- Dis/Enable to load from Store every time when the menu is expanded.

For usage and getting the source, click here (http://joekuan.wordpress.com/2011/04/11/an-enhanced-version-of-ext-ux-menu-storemenu/)

Thanks
Joe

gigel
12 Apr 2011, 4:14 AM
I've modified the original code, so that items get automatically turned into StoreMenus if they have the "menuId" attribute set:



Ext.namespace('Ext.ux.menu');

Ext.ux.menu.StoreMenu = function(config) {
Ext.ux.menu.StoreMenu.superclass.constructor.call(this,config);
this.baseParams = config.baseParams || {};
if(!this.store){
//at least url/proxy or data need to be given in config when initiating this component
this.store = new Ext.data.SimpleStore({
fields: ['config'],
url: this.url,
baseParams: this.baseParams
/*,
proxy:this.proxy,
data: this.data
*/
});
}
// Keep track of what menu items have been added
this.storeMenus = [];
if (this.itemsOffset === undefined) {
this.itemsOffset = 0;
}
this.on('show', this.onMenuLoad, this);
this.store.on('beforeload', this.onBeforeLoad, this);
this.store.on('load', this.onLoad, this);
};

Ext.extend(Ext.ux.menu.StoreMenu, Ext.menu.Menu, {
loadingText: Ext.LoadMask.prototype.msg || 'Loading...',
loaded: false,

onMenuLoad: function(){
if(!this.loaded || this.autoReload){
//if(this.options) {
//this.store.loadData(this.options);
//}
//else {
this.store.load();
//}
}
},

updateMenuItems: function(loadedState,records) {
//var visible = this.isVisible();
//this.hide(false);

for (var i = 0; i < this.storeMenus.length; i++) {
this.remove(this.storeMenus[i]);
}
this.storeMenus = [];

//to sync the height of the shadow
this.el.sync();

if (loadedState) {
for(var i=0, len=records.length; i<len; i++){
//create a real function if a handler or menu is given as a string (because a function cannot really be encoded in JSON
if (records[i].json.handler) {
eval("records[i].json.handler = "+records[i].json.handler);
//records[i].json.handler = new Function(records[i].json.handler);
} else if (this.itemsHandler) {
records[i].json.handler = this.itemsHandler;
}

if (records[i].json.menu) {
eval("records[i].json.menu = "+records[i].json.menu);
//records[i].json.menu = new Function(records[i].json.menu);
}
//console.log([this, records[i]]);
if (records[i].json.menuId) {
records[i].json.menu = new Ext.ux.menu.StoreMenu({
url: this.initialConfig.url,
menuId: records[i].json.menuId
});
}

this.storeMenus.push(this.insert(this.itemsOffset + i, records[i].json));
}
//this.hide();
//this.show();
}
else {
this.storeMenus.push(this.insert(this.itemsOffset + i,'<span class="loading-indicator">' + this.loadingText + '</span>'));
}

this.loaded = loadedState;
//if(visible && loadedState) {
//this.show(this.getEl().getXY());
//this.show();
//}
},
onBeforeLoad: function(store){
this.store.baseParams = this.baseParams;
this.store.baseParams.menuId = this.menuId;
this.updateMenuItems(false);
},
onLoad: function(store, records){
this.updateMenuItems(true,records);
},
setItemsHandler: function(handler) {
this.itemsHandler = handler;
},
setOffset: function(offset) {
this.itemsOffset = offset;
},
setAutoReload: function(autoReload) {
this.autoReload = autoReload;
}
});

xorge2
15 Jun 2011, 7:52 AM
I've got a n00b question. How do I add this wonderful widget to my current project. Thanks guys.

wm003
16 Aug 2011, 9:49 PM
I've got a n00b question. How do I add this wonderful widget to my current project. Thanks guys.
Please take a look at post #1 (http://www.sencha.com/forum/showthread.php?61674-Ext.ux.menu.StoreMenu-Ajax-Store-as-menu-item-config&p=297239&viewfull=1#post297239) . Check out the demopage to have an idea of implementation.

momerak
5 Jun 2012, 8:24 AM
someone could send some sources in extjs4 example implementation. thanks

ImShogun
13 Jun 2012, 4:25 AM
Hi all,

Special thanks to wm003 for this great Ext 3 plugin, and also thanks to Wojtekn for porting it to Ext 4 (https://github.com/wojtekn/Ext.ux.menu.StoreMenu),

I tried both the original 1.2 and Ext 4 port without success under Ext 4.1, so here is the one I could successfully use:

Regards!




/*
* Ext.ux.menu.StoreMenu Addon
*
* @author Marco Wienkoop (wm003/lubber)
* @copyright (c) 2009, Marco Wienkoop (marco.wienkoop@lubber.de) http://www.lubber.de
*
* @class Ext.ux.menu.StoreMenu
* @extends Ext.menu.Menu

* Donations are always welcome :)
* Any amount is greatly appreciated and will help to continue on developing ExtJS Widgets
*
* You can donate via PayPal to donate@lubber.de
*
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.

This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.

You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>

* This Addon requires the ExtJS Library, which is distributed under the terms of the GPL v3 (from V2.1)
* See http://extjs.com/license for more info


Revision History
v 0.2 [2009/03/04]
- added support for submenu ("menu" has to be delivered such as "handler")

v 0.1 [2009/03/03]
Initial release
*/

/*
Modified by Joe Kuan - kuan.joe@gmail.com
Ported to Ext 4 by Wojciech Naruniec - w.naruniec@gmail.com
13/06/2012: Ported to Ext 4.1 by Laurent Chenet - laurent.chenet@gmail.com (Tested only with parameter 'url')
*/

Ext.namespace('Ext.ux.menu');
Ext.define('Ext.ux.menu.StoreMenu', {
extend: 'Ext.menu.Menu',
initComponent: function(){
this.initConfig();
// call parent
this.callParent(arguments);
// Keep track of what menu items have been added
this.storeMenus = [];
if (this.itemsOffset === undefined) {
this.itemsOffset = 0;
};
this.on('render', this.onMenuLoad, this);
if (!this.store) {
//at least url/proxy or data need to be given in config when initiating this component
this.store = new Ext.data.Store({
proxy:{
type:'ajax',
url: this.url,
reader:{
type:'json'
}
},
fields: ['config'],
baseParams: this.baseParams
});
};
this.store.on('beforeload', this.onBeforeLoad, this);
this.store.on('load', this.onLoad, this);
},
loadingText: Ext.LoadMask.prototype.msg || 'Loading...',
loaded: false,
onMenuLoad: function(){
if (!this.loaded || this.autoReload) {
this.store.load();
XXX = this.store;
};
},
updateMenuItems: function(loadedState, records){
for (var i = 0; i < this.storeMenus.length; i++) {
this.remove(this.storeMenus[i]);
}
this.storeMenus = [];
if (loadedState) {
for (var i = 0, len = records.length; i < len; i++) {
//create a real function if a handler or menu is given as a string (because a function cannot really be encoded in JSON
if (records[i].raw.handler) {
eval("records[i].raw.handler = " + records[i].raw.handler);
}
else if (this.itemsHandler) {
records[i].raw.handler = this.itemsHandler;
};
if (records[i].raw.menu) {
eval("records[i].raw.menu = " + records[i].raw.menu);
};
this.storeMenus.push(this.insert(this.itemsOffset + i, records[i].raw));
}
}
else {
this.storeMenus.push(this.insert(this.itemsOffset + i, '<span class="loading-indicator">' + this.loadingText + '</span>'));
};
this.loaded = loadedState;
},
onBeforeLoad: function(store){
this.updateMenuItems(false);
},
onLoad: function(store, records){
this.updateMenuItems(true, records);
},
setItemsHandler: function(handler){
this.itemsHandler = handler;
},
setOffset: function(offset){
this.itemsOffset = offset;
},
setAutoReload: function(autoReload){
this.autoReload = autoReload;
},
setBaseParam: function(param, value){
this.store.setBaseParam(param, value);
},
setStore: function(store){
this.store = store;
}
});



The expected typical config of menu item is:




{
text: 'Grid Viewer',
menu: new Ext.ux.menu.StoreMenu({
url: 'yoururl'
})
}



Example of json answer:




[{"text":"Playground dummy node","iconCls":"light_bulb","handler":"function(item) {gridViewerObj.OpenGridViewTab(9999,'light_bulb',\"Playground dummy node\");}","id_node_type":9999},{"text":"Annual Programme for Delegation","iconCls":"folder","handler":"function(item) {gridViewerObj.OpenGridViewTab(1,'folder',\"Annual Programme for Delegation\");}","id_node_type":1},{"text":"Domain","iconCls":"topic","handler":"function(item) {gridViewerObj.OpenGridViewTab(2,'topic',\"Domain\");}","id_node_type":2},{"text":"Decentralized programme","iconCls":"mail_send","handler":"function(item) {gridViewerObj.OpenGridViewTab(15,'mail_send',\"Decentralized programme\");}","id_node_type":15},{"text":"Programme","iconCls":"note_book","handler":"function(item) {gridViewerObj.OpenGridViewTab(3,'note_book',\"Programme\");}","id_node_type":3},{"text":"Decision","iconCls":"light_bulb","handler":"function(item) {gridViewerObj.OpenGridViewTab(4,'light_bulb',\"Decision\");}","id_node_type":4},{"text":"Decentralized decision","iconCls":"light_bulb","handler":"function(item) {gridViewerObj.OpenGridViewTab(16,'light_bulb',\"Decentralized decision\");}","id_node_type":16},{"text":"Component","iconCls":"puzzle","handler":"function(item) {gridViewerObj.OpenGridViewTab(12,'puzzle',\"Component\");}","id_node_type":12},{"text":"Priority Axis","iconCls":"warning","handler":"function(item) {gridViewerObj.OpenGridViewTab(5,'warning',\"Priority Axis\");}","id_node_type":5},{"text":"Focal Area","iconCls":"search","handler":"function(item) {gridViewerObj.OpenGridViewTab(6,'search',\"Focal Area\");}","id_node_type":6},{"text":"Sector","iconCls":"search","handler":"function(item) {gridViewerObj.OpenGridViewTab(7,'search',\"Sector\");}","id_node_type":7},{"text":"Project","iconCls":"note","handler":"function(item) {gridViewerObj.OpenGridViewTab(8,'note',\"Project\");}","id_node_type":8},{"text":"Sub-Project","iconCls":"note_book","handler":"function(item) {gridViewerObj.OpenGridViewTab(13,'note_book',\"Sub-Project\");}","id_node_type":13},{"text":"Activity-Envelope","iconCls":"mail_send","handler":"function(item) {gridViewerObj.OpenGridViewTab(14,'mail_send',\"Activity-Envelope\");}","id_node_type":14},{"text":"Procurement","iconCls":"shopping_cart","handler":"function(item) {gridViewerObj.OpenGridViewTab(9,'shopping_cart',\"Procurement\");}","id_node_type":9},{"text":"Contract","iconCls":"edit_page","handler":"function(item) {gridViewerObj.OpenGridViewTab(10,'edit_page',\"Contract\");}","id_node_type":10},{"text":"Financial Memorandum","iconCls":"mail_send","handler":"function(item) {gridViewerObj.OpenGridViewTab(17,'mail_send',\"Financial Memorandum\");}","id_node_type":17},{"text":"Payment","iconCls":"euro_currency_sign","handler":"function(item) {gridViewerObj.OpenGridViewTab(11,'euro_currency_sign',\"Payment\");}","id_node_type":11},{"text":"Objectives","iconCls":"search","handler":"function(item) {gridViewerObj.OpenGridViewTab(18,'search',\"Objectives\");}","id_node_type":18},{"text":"Decentralized project","iconCls":"note","handler":"function(item) {gridViewerObj.OpenGridViewTab(19,'note',\"Decentralized project\");}","id_node_type":19},{"text":"Local contract","iconCls":"edit_page","handler":"function(item) {gridViewerObj.OpenGridViewTab(20,'edit_page',\"Local contract\");}","id_node_type":20},{"text":"Local payment","iconCls":"euro_currency_sign","handler":"function(item) {gridViewerObj.OpenGridViewTab(21,'euro_currency_sign',\"Local payment\");}","id_node_type":21}]

luisparada
28 Jun 2012, 7:18 AM
Is it possible to use it with extjs 4.1 ??? Is the posted code tested with it ??

ImShogun
29 Jun 2012, 5:52 AM
Yes, it is working under 4.1. I edited my previous post with the methods I'm using. I also fixed the store type because I suspect my first release was not working properly without the compatibility layer (sorry for that)