背景: 私たちのアプリは常に全体として圧縮されていますが、ユーザー アクセスによってサーバー側のアクションが制限される場合があります。アプリの起動時に、どのアクションが許可されているかがわかります。ここで、アクセス権のないユーザーからすべてのビュー (パネル、ボタンなど) を非表示にしたいと考えています。
そのために、任意のコンポーネントに適用できるプラグインを作成しました。しかし、ここに問題があります:
プラグインホストに対して実行しようとしているものは次のとおりです。
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.
});