Custom Resized Portlets using Sencha GXT 3.1 Beta

Sencha makes a container called the PortalLayoutContainer available through its API which allows the developer to add portlets to the container. The container extends the VerticalLayoutContainer and works by the user adding portlet widgets to the container in predefined column widths. The PLC doesn’t allow users to specify a grid with a predefined portlet height so that portlets dropped in will fit that size. Hence, we had some portlets that didn’t render nicely because they were too big for screens with low vertical resolutions. Also, because we don’t know what kind of screen resolution our users are going to use, we couldn’t just set a fixed height and forget about it.

In other words, sometimes one just wants to add a portlet that say, takes up 50% of the vertical screen real-estate rather than a fixed 450px. How did I solve this problem? Disclaimer: I admit that this solution is a bit of a hack, but without any other exposed API I did what I had to do.

Where's the rest of my portlet?
Where’s the rest of my portlet?

Solution: I had to resort to event handlers that listened for a resize of the PortalLayoutContainer. Essentially what this method does is traverse up the widget hierarchy until it finds a PortalLayoutContainer, then binds a resize handler for the specific portlet to the PLC. When the resize event is triggered on the PLC, each individual portlet is resized based on the initial parameter of how much screen real estate the portlet should take up. I also set a minimum size so that the portlets would not continue to resize if the overall PLC got too small (where the data started looking bad). You could easily set a maximum size as well so the portlets would not continue resizing after a certain point.

/**
	 * Attaches a resizeHandler to the parent (which is assumed to be a PortalLayoutContainer
	 * You need to call this method after the _portlet is added to the container
	 * @param width - the percentage of width of the window to resize to
	 * @param height - the percentage of height of the window to resize to
	 */
	public void bindResizeHandler(final double width, final double height) {
		if (_portlet != null) {
			_config.setResizable(Boolean.TRUE);
			
			//traverse up widget hierarchy until we reach PortalLayoutContainer
			Widget w = _portlet.getParent();
			while (w != null && !(w instanceof PortalLayoutContainer)) {
				w = w.getParent();
			}
			
			//Resize
			PortalLayoutContainer plc = ((PortalLayoutContainer) w);
			if (plc != null) {
				plc.addResizeHandler(new ResizeHandler () {

					@Override
					public void onResize(ResizeEvent event) {
						int newWidth = Math.max((int) (event.getWidth() * width) - 10, _config.getMinWidth());
						int newHeight = Math.max((int) (event.getHeight() * height) - 10, _config.getMinHeight());
						
						//Only resize if width or height > minWidth or minHeight - note min width doesn't quite work right
						//because GXT widgets still try to autoresize
						if (_config.getWidth() != newWidth || _config.getHeight() != newHeight) {
							_config.setWidth(newWidth);
							_config.setHeight(newHeight);
							resize(_config.getWidth(), _config.getHeight());
						}
					}
					
				});
			}
		}
	}
	
	@Override
	public void resize(int width, int height) {
		if (_config.getResizable()) {
			_portlet.setWidth(width);
			_portlet.setHeight(height);
			_portlet.forceLayout();
		}
	}

I know that this turns the portal container into more of a “dashboard,” but that’s what our requirements called for. If you want a portlet to have a fixed size, simply don’t bind the handler to that specific portlet and the height will remain fixed.

Here’s how I bound each portlet to the PLC during instantiation.

//a PLC is made with two columns, each 50% and one column that's 100% (a hack to get a 50/50/100 split
			_portalContainer = new PortalLayoutContainer(3);
			_portalContainer.setColumnWidth(0, .5);
			_portalContainer.setColumnWidth(1, .5);
			_portalContainer.setColumnWidth(2, 1);
			_updateList = new ArrayList<UpdateablePortlet>();

//A portlet config is my own object that has parameters like whether the portlet is resizable and options specific to the data used to populate the portlet
			PortletConfig _tjpConfig = new PortletConfig();
			_tjp = new TestJobsPortlet(_tjpConfig);
			_portalContainer.add(_tjp.asWidget(), 1);

//This will add the portlet to the top right corner of the PLC and bind a resize handler to take up 50% of the width and 50% of the height (i.e. 1/4 of the screen) whenever the PLC is resized
			_tjp.bindResizeHandler(.5, .5);

And here’s the result:

much better!
much better!

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out /  Change )

Google photo

You are commenting using your Google account. Log Out /  Change )

Twitter picture

You are commenting using your Twitter account. Log Out /  Change )

Facebook photo

You are commenting using your Facebook account. Log Out /  Change )

Connecting to %s