Prevent rendering (hide and / or disable) the component at build time

Reference Information. Our application is always packaged as a whole, but through users access to certain server-side actions may be limited. We know what actions are allowed when the application starts. Now we want to hide all views (panels, buttons, etc.) from the user to whom he does not have access.

To do this, we created a plugin that can be applied to any component. But here there are problems:

Here is what we are trying to do against the host of the plugin:

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; }) 

At first, we thought that the sooner we do this, the better. Therefore, we tried to launch it during the construction of the plugin. But this was not possible, because the listeners (of the host) did not seem to be ready yet (the component is trying to fire the hide event). Therefore, we moved it to the init method of the plugin, which did not throw an error, but simply partially worked. Only the beforerender event beforerender began to apply, but it only interrupted the child’s rendering. so we got a broken component (there are borders, but no content). If we commented on the event registration, the host remained untouched. We also tested using only hidden:true and disabled:true with no luck.

So, how can we prevent component rendering correctly?

Edit:

The component must be marked as disabled and hidden, because we cannot prevent the creation of the component. I cut me off from my colleague, was wrong, so the call to setVisible(false) worked, we assume disable() . But the component becomes motionless, and we seem to really be unable to veto it without getting half the processed component.

Answer by @AlexTokarev

I tried what @AlexTokarev suggested. To do this, I added the following lines to the constructor plugin

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

Based on debugging, I know that settings are applied very early (in Ext.AbstractComponent.constructor ), but I still end up with a hidden and visualized component.

enter image description here

Comment by @sbgoran

In one test folder, we use a column layout in which all containers are distributed from the same class. As soon as I add my plugin (with the beforerender event returning a false configuration) to one of these expanding containers (the plugin is added directly to the class definition (like ptype)), all containers in these columns look broken (only the borders are displayed and the contents are a little gray boxes in the upper left corner.). Thus, interrupted rendering affects all children of the column when only one child cancels the rendering.

** Code Example **

Firstly, I want to note that we are looking for a way to do this in the general case, as far as we know that rendering in ExtJS is one thing. I can ask to install a demo, but I think that it will not be so simple, because we use Ext.app.portal.Panel for an unsuccessful example. but the plugin should work for any kind of Component. First I will add a demo code:

We have a view that fits into Viwport with a frame layout.

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

Inside the controller, we fill this

 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); 

Here is the portal panel

 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(); } }); 

And here is the Portlet

 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 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 }); } } }); 

Here is an example view

 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*/ ] }); 

Here is the plugin

 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 */ }); 

Here is the column layout

Ext.define ('MVC.app.portal.PortalColumn', {expand: "Ext.container.Container", alias: '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. 

});

+8
extjs
source share
3 answers

Have you tried to set autoRender: true in your add- autoRender: true ? Here's the doc: http://docs.sencha.com/extjs/4.2.2/#!/api/Ext.AbstractComponent-cfg-autoRender

+3
source share

You can try to hide and show functions, and also try with the "added" event listener, which will be called after adding the component to the container.

+1
source share

Try something like this for your plugin:

 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 */ }); 
+1
source share

All Articles