扩展的ExtJS类找不到自定义侦听器功能 - “oe is undefined”

时间:2009-12-09 16:41:44

标签: extjs

我正在向TreePanel添加自定义上下文菜单。 当我为上下文菜单设置单独的函数时,这一切都正常工作,但是如果我点击其中一个选项然后再次查看上下文菜单,我遇到的问题是上下文菜单项最终会加倍/三倍。

我浏览了其他上下文菜单示例,并提出了this one by Aaron Conran我几乎“偷”了批量添加了一些东西,将函数直接添加到Ext.ext.treePanel配置中。这给了我一个关于“oe is undefined”的错误,它似乎在树配置中引用了“contextmenu:this.onContextMenu”。

我认为这可能与我定义所有这些的方式有关,所以我决定将Ext.ext.TreePanel与我的函数一起扩展为一个学习练习。

不幸的是,当页面试图构建TreePanel时,我已经设法解决了扩展TreePanel的问题,现在又回到了“oe is undefined”。我已经浏览了一下,我不确定是什么导致了这个问题,所以任何帮助或建议都会非常感激。

以下是用于定义/构建树面板的代码。我希望它不会太可怕。

siteTree = Ext.extend(Ext.tree.TreePanel,{
        constructor : function(config){
            siteTree.superclass.constructor.call(this, config);
        },
        onContextMenu: function(n,e){
        if (!this.contextMenu){
            console.log('treeContextMenu',n,e);

            if (n.parentNode.id == 'treeroot'){
                var menuitems = [{text:'Add Child',id:'child'}];
            } else {
                var menuitems = 
                        [{text:'Add Child',id:'child'},
                         {text:'Add Above',id:'above'},
                         {text:'Add Below',id:'below'}];
            }

            this.contextMenu = new Ext.menu.Menu({
                id:'treeContextMenu',
                defaults :{
                    handler : treeContextClick,
                    fqResourceURL : n.id
                },
                items : menuitems
            });
        }
        var xy = e.getXY();
        this.contextMenu.showAt(xy);
    }           
});

var treePanel = new siteTree({
    id: 'tree-panel',
    title : 'Site Tree',
    region : 'center',
    height : 300,
    minSize: 150,
    autoScroll: true,

    // tree-specific configs:
    rootVisible: false,
    lines: false,
    singleExpand: true,
    useArrows: true,

    dataUrl:'admin.page.getSiteTreeChildren?'+queryString,
    root: {
        id: 'treeroot',
        nodeType: 'async',
        text: 'nowt here',
        draggable: false
    },
    listeners:{
        contextmenu: this.onContextMenu
    }
});

总而言之;在我的上下文菜单功能中有更好的方法吗?

  

if(n.parentNode.id =='treeroot'){   基本上,如果点击的节点是顶级我只想给用户一个添加子选项,而不是在上面/下面添加。

提前感谢您的帮助

5 个答案:

答案 0 :(得分:5)

在您的siteTree类的实例化中,您有:

listeners: {
    contextmenu: this.onContextMenu
}

但是,在实例化时,this.onContextMenu并未指向您在siteTree中定义的onContextMenu方法。

修复它的一种方法是从包装函数中调用该方法:

listeners: {
    contextmenu: function() {
        this.onContextMenu();
    }
}

假设你没有覆盖监听器配置中的范围'this'将指向执行监听器时的siteTree实例。

但是,既然您已经在siteTree类中定义了上下文菜单,那么您也可以在那里定义监听器:

constructor: function( config ) {
    siteTree.superclass.constructor.call(this, config);
    this.on('contextmenu', this.onContextMenu);
}

确保使用树删除上下文菜单也是一个好主意。这使您的siteTree定义:

var siteTree = Ext.extend(Ext.tree.TreePanel, {
    constructor: function( config ) {
        siteTree.superclass.constructor.call(this, config);
        this.on('contextmenu', this.onContextMenu);
        this.on('beforedestroy', this.onBeforeDestroy);
    },
    onContextMenu: function( node, event ) {
        /* create and show this.contextMenu as needed */
    },
    onBeforeDestroy: function() {
        if ( this.contextMenu ) {
            this.contextMenu.destroy();
            delete this.contextMenu;
        }
    }
});

答案 1 :(得分:1)

昨天我遇到了这个问题。上下文菜单中重复项和重复项的问题是由于extjs向具有相同ID的页面添加多个元素。每次调用this.contextMenu.showAt(xy)时,都会向页面添加ID为“treeContextMenu”的div。大多数浏览器,特别是IE,处理这个问题很糟糕。解决方案是在添加新的上下文菜单之前删除旧的上下文菜单。

以下是我的代码的删节版本:

var old = Ext.get("nodeContextMenu");
if(!Ext.isEmpty(old)) {
    old.remove();
}
var menu = new Ext.menu.Menu({
    id:'nodeContextMenu',
    shadow:'drop',
    items: [ ... ]
});
menu.showAt(e.xy);

答案 2 :(得分:1)

我建议永远不要使用硬编码ID。 @aplumb建议清理DOM以重用现有ID。好的,但是当你不再需要DOM中的小部件/元素时,我建议你清理DOM 你应该永远不会重用ID

var someId = Ext.id( null, 'myWidgetId' );
var someElement = new SuperWidget({
    id: someId,
    ...
});

答案 3 :(得分:1)

只是添加到猫头鹰的答案

这一点:

listeners: {
  contextmenu: this.onContextMenu
}

在加载javascript文件时执行。该阶段的this很可能指向窗口对象。

答案 4 :(得分:1)

修复它的一个简单方法是在上下文菜单的hide事件中添加监听器,这样就可以销毁它。

new Ext.menu.Menu(
  {
    items:[...],
    listeners: { hide: function(mn){ mn.destroy(); } }
  }
).show(node.ui.getAnchor());