9

背景: 私たちのアプリは常に全体として圧縮されていますが、ユーザー アクセスによってサーバー側のアクションが制限される場合があります。アプリの起動時に、どのアクションが許可されているかがわかります。ここで、アクセス権のないユーザーからすべてのビュー (パネル、ボタンなど) を非表示にしたいと考えています。

そのために、任意のコンポーネントに適用できるプラグインを作成しました。しかし、ここに問題があります:

プラグインホストに対して実行しようとしているものは次のとおりです。

if (cmp['setVisible']) cmp.setVisible(false); else cmp.hidden = true;
if (cmp['disable']) cmp.disable(); else cmp.disabled = true;
cmp.on('beforerender', function() { return false; })

まず、これは早ければ早いほどよいと考えました。そのため、プラグインの構築時に実行しようとしました。しかし、(ホストの) リスナーがまだ準備ができていないように見えるため、それは不可能でした (コンポーネントは非表示イベントを起動しようとします)。initそのため、エラーをスローせず、部分的にしか機能しないプラグインのメソッドに移動しました。イベントのみbeforerenderが実際に適用されましたが、子のレンダリングが中止されただけです。そのため、壊れたように見えるコンポーネントになりました (境界線はありますが、コンテンツはありません)。イベント登録をコメントアウトした場合、主催者はそのままでした。hidden:trueまた、 andのみの使用もテストしましたが、disabled:trueうまくいきませんでした。

では、正しい方法でコンポーネントのレンダリングを防ぐにはどうすればよいでしょうか?

編集:

コンポーネントの作成を防ぐことはできないため、コンポーネントは無効化および非表示としてフラグを立てる必要があります。同僚から受け取った切り取りが間違っていたので、 の呼び出しも機能したsetVisible(false)と思いdisable()ます。しかし、コンポーネントは静止レンダリングされ、半分レンダリングされたコンポーネントで終わることなく、これを拒否することは実際にはできないようです.

@AlexTokarevによる回答

@AlexTokarevが提案したことを試しました。そのために、次の行を Plugin-Constructor に追加しました

cmp.hidden = true;
cmp.autoShow = false; // I know this may do nothing for non floating but I added it anyway
cmp.autoRender = true;

デバッグに基づいて、設定が非常に早い段階で ( Ext.AbstractComponent.constructorで) 適用されることはわかっていますが、最終的にはコンポーネントが非表示になり、レンダリングされます。

ここに画像の説明を入力

@sbgoran によるコメント

1 つのテストケースでは、すべてのコンテナーが同じクラスから拡張される列レイアウトを使用します。プラグインをこの拡張コンテナーの 1 つに (false 構成を返す beforerender イベントを使用して) 追加するとすぐに (プラグインは (ptype として) クラス定義に直接追加されます)、この列内のすべてのコンテナーが壊れているように見えます (境界線のみがレンダリングされ、内容は左上隅の小さな灰色のボックスです。) そのため、1 つの子アイテムのみがレンダリングがキャンセルされた場合、中止されたレンダリングは列のすべての子アイテムに影響します。

**サンプルコード**

最初に、ExtJS でのレンダリングが 1 つのことであることがわかっている限り、一般的な原因でこれを行う方法を探していることに注意してください。Ext.app.portal.Panelデモのセットアップを依頼することはできますが、失敗例にを使用しているため、これはそれほど簡単ではないと思います。しかし、プラグインはあらゆる種類のコンポーネントで機能するはずです。まず、いくつかのデモ コードを追加します。

ボーダーレイアウトのビューポートに配置されたビューがあります

Ext.define('MVC.view.Application',{
    extend:'Ext.tab.Panel',
    alias:'widget.appview',
    region: 'center',
    activeTab: 1
});

コントローラー内でこれを埋めます

var portal = this.portalRef = Ext.widget('portalpanel', {
    title: 'Employee',
    portalCols: 2
});
portal.addPortlet(0,['employee','employee2','employee3']);
portal.addPortlet(1,['employee4','employee5']);
app.appviewmain.add(portal);

ポータルパネルはこちら

Ext.define('MVC.app.portal.PortalPanel', {
    extend: 'Ext.panel.Panel',
    alias: 'widget.portalpanel',

    requires: [
        'Ext.layout.container.Column',
        'Ext.app.portal.PortalDropZone',
        'Ext.app.portal.PortalColumn'
    ],

    portalCols: 2,

    portalColCfg: {
        defaults: {
            closable: false,
            draggable: false,
            collapsible: false,
            header: false,
            bodyStyle: {
                background: '#fff',
                padding: '10px'
            }
        },
        items: []
    },

    addPortlet: function(idx, portlets) {
        if (idx > this.portalCols || idx < 0)
            return;
        var portalCol = this.items.getAt(idx);
        function insertPortlet(portlet) {
            if (Ext.isString(portlet)) {
                portlet = { xtype: portlet };
            }
            portalCol.add(portlet);
        };

        if (Ext.isArray(portlets)) {
            var len = portlets.length,
                i = 0;
            for(;i<len;i++) {
                insertPortlet(portlets[i]);
            }
        }  else  {
            insertPortlet(portlets);
        }

    },

    initPortal: function() {
        var cfg = this.portalColCfg,
            i = 0,
            cols = [];
        for (;i<this.portalCols;i++) {
            cols.push(Ext.clone(cfg));
        }
        this.items = cols;
    },

    cls: 'x-portal',
    bodyCls: 'x-portal-body',
    defaultType: 'portalcolumn',
    autoScroll: true,

    manageHeight: false,

    initComponent : function() {
        var me = this;
        // init only if nothing is defined
        if (!me.items)
            me.initPortal();

        // Implement a Container beforeLayout call from the layout to this Container
        me.layout = {
            type : 'column'
        };
        me.callParent();

        me.addEvents({
            validatedrop: true,
            beforedragover: true,
            dragover: true,
            beforedrop: true,
            drop: true
        });
    },

    // Set columnWidth, and set first and last column classes to allow exact CSS targeting.
    beforeLayout: function() {
        var items = this.layout.getLayoutItems(),
            len = items.length,
            firstAndLast = ['x-portal-column-first', 'x-portal-column-last'],
            i, item, last;

        for (i = 0; i < len; i++) {
            item = items[i];
            item.columnWidth = 1 / len;
            last = (i == len-1);

            if (!i) { // if (first)
                if (last) {
                    item.addCls(firstAndLast);
                } else {
                    item.addCls('x-portal-column-first');
                    item.removeCls('x-portal-column-last');
                }
            } else if (last) {
                item.addCls('x-portal-column-last');
                item.removeCls('x-portal-column-first');
            } else {
                item.removeCls(firstAndLast);
            }
        }

        return this.callParent(arguments);
    },

    // private
    initEvents : function(){
        this.callParent();
        this.dd = Ext.create('Ext.app.portal.PortalDropZone', this, this.dropConfig);
    },

    // private
    beforeDestroy : function() {
        if (this.dd) {
            this.dd.unreg();
        }
        this.callParent();
    }
});

そしてポートレットはこちら

Ext.define('Ext.app.portal.Portlet', {
    extend: 'Ext.panel.Panel',
    alias: 'widget.portlet',

    layout: 'fit',
    anchor: '100%',
    frame: true,
    closable: true,
    collapsible: true,
    animCollapse: true,
    draggable: {
        moveOnDrag: false    
    },
    cls: 'x-portlet',

    initComponent : function() {
        this.callParent();
    },

    // Override Panel's default doClose to provide a custom fade out effect
    // when a portlet is removed from the portal
    doClose: function() {
        if (!this.closing) {
            this.closing = true;
            this.el.animate({
                opacity: 0,
                callback: function(){
                    var closeAction = this.closeAction;
                    this.closing = false;
                    this.fireEvent('close', this);
                    this[closeAction]();
                    if (closeAction == 'hide') {
                        this.el.setOpacity(1);
                    }
                },
                scope: this
            });
        }
    }
});

ここにサンプルビューがあります

Ext.define('MVC.view.employee.Employee',{
    extend:'Ext.app.portal.Portlet',
    alias:'widget.employee',
    plugins: [{ptype: 'directbound', accessRoute: 'Employee.Read'}],
    items: [
        /*A form with some fields*/
    ]
});

プラグインはこちら

Ext.define('MVC.direct.plugins.DirectBound',{
    extend: 'Ext.AbstractPlugin',
    alternateClassName: ['MVC.direct.DirectBound'],
    alias: 'plugin.directbound',

    /**
     * @cfg {int} blockMode Indicates the way in which the Component gets blocked
     * options
     * 0 hide and disable
     * 1 disable
     */
    blockMode: 1,

    constructor: function(config) {
        var me = this,
            cmp = config['cmp'], 
            route;
        me.parseRoute(route);

        // check for access
        if (!me.checkAccess()) {
            if (me.blockMode === 0) {
                cmp.hidden = true;
                cmp.autoShow = false;
                cmp.autoRender = true;
            }
            me.diabled = true;
        }

        me.callParent(arguments);
    }

    /* some more methods */
});

これが列のレイアウトです

Ext.define('MVC.app.portal.PortalColumn', { 拡張: 'Ext.container.Container', エイリアス: 'widget.portalcolumn',

requires: [
    'Ext.layout.container.Anchor',
    'MVC.app.portal.Portlet'
],

layout: 'anchor',
defaultType: 'portlet',
cls: 'x-portal-column'

// This is a class so that it could be easily extended
// if necessary to provide additional behavior.

});

4

3 に答える 3

3

autoRender: trueオプションのコンポーネントを設定しようとしましたか? ドキュメントは次のとおりです: http://docs.sencha.com/extjs/4.2.2/#!/api/Ext.AbstractComponent-cfg-autoRender

于 2013-10-08T18:39:53.933 に答える
1

プラグインで次のようなことを試してください。

Ext.define('MVC.direct.plugins.DirectBound',{
    extend: 'Ext.AbstractPlugin',
    alternateClassName: ['MVC.direct.DirectBound'],
    alias: 'plugin.directbound',

    /**
     * @cfg {int} blockMode Indicates the way in which the Component gets blocked
     * options
     * 0 hide and disable
     * 1 disable
     */
    blockMode: 1,

    constructor: function(config) {
        var me = this,
            cmp = config['cmp'], 
            route;
        me.parseRoute(route);

        // Try to define beforerender callback on component and return false if
        // component should not be visible
        cmp.on('beforerender', function() {
            if (!me.checkAccess()) {
                if (me.blockMode === 0) {
                    return false;
                }

                // Not sure what this do for you but it wont disable component
                // if you want your component disabled here try cmp.disable()
                me.diabled = true;
            }
        });

        // Maybe this code is not needed anymore
        // check for access
        if (!me.checkAccess()) {
            if (me.blockMode === 0) {
                cmp.hidden = true;
                cmp.autoShow = false;
                cmp.autoRender = true;
            }
            me.diabled = true;
        }

        // This should stay for sure
        me.callParent(arguments);
    }

    /* some more methods */
});
于 2013-10-10T08:14:22.900 に答える
1

非表示機能と表示機能を試すことができます。また、コンポーネントをコンテナーに追加した後に呼び出される「追加された」イベントリスナーを試すこともできます。

于 2013-10-08T11:46:12.650 に答える