Search

Mobile tag

About Me

I am the "IBM Collaboration & Productivity Advisor" for IBM Asia Pacific. I'm based in Singapore.
Reach out to me via:
Follow notessensei on Twitter
(posts)
Skype
Sametime
IBM
Facebook
LinkedIn
XING
Amazon Store
Amazon Kindle

Twitter

Domino Upgrade

VersionSupport end
5.0
6.0
6.5
7.0
8.0
8.5
Upgrade to 9.x now!
(see the full Lotus lifcyle) To make your upgrade a success use the Upgrade Cheat Sheet.
Contemplating to replace Notes? You have to read this! (also available on Slideshare)

Languages

Other languages on request.

Visitors

Useful Tools

Get Firefox
Use OpenDNS
The support for Windows XP has come to an end . Time to consider an alternative to move on.

« Learning Java | Main| The AppStore wars »

Taming the jumpy categorized Views in XPages

QuickImage I am not a fan of categorized views in web applications and have suggested alternative uses before. However beautiy is in the eye of the beholder, so categorized views are used. When a category is rendered it sits on its own tablerow (tr) in a tabletag (td) that has a colspan attribute. This effectively disables the column width settings for your view until you expand the category to show a full row of data resulting in some "screen jumping". While that won't sink the Titanic it is a little odd. Short of rolling your own rendering using a repeat control, there is a fix consisting of 2 JavaScript functions (one for the server, one for the client and a little addition in the source code panel. This works in all categorized views. However when you have a column with a column total rendering might be different since XPages doesn't render the colspan attribute then. Lets get started. Open your source pane and locate the view panel and the xp:this.facets. Here you insert a scriptBlock like this:
  1. {xp:this.facets}
  2.     {xp:pager partialRefresh="true" layout="Previous Group Next"
  3.     xp:key="headerPager" id="pager1"}
  4.     {/xp:pager}
  5.      {xp:scriptBlock xp:key="south" id="scriptBlock1"}
  6.     {xp:this.value}{![CDATA[#{javascript:return getClientJSforTableLayout("viewPanel1");} ] ] }{/xp:this.value}
  7.      {/xp:scriptBlock}
  8. {/xp:this.facets}
(Replace { } with < and > except inside the CDATA section). Then you add 2 JavaScript libraries to your XPage: CatViewPatches.js and TableSupportFunctions.jss. They will fix the column width. One caveat: you have to specify the width for all columns otherwise the unspecified columns get 100/{number-of-columns}% width assigned.
The ServerSide JS:
  1. function getClientJSforTableLayout(tableID) {
  2.     /**
  3.       * This code has as result JavaScript source code that is send down to the client]
  4.     */
  5.     var curTable = getComponent("viewPanel1");
  6.     var curID = getClientId("viewPanel1");
  7.     var tablewidth = extractWidthFromStyle(curTable.viewStyle);
  8.     var result = "fixCatTableWidth(\""; // This holds the JavaScript we return to the browser
  9.     result += curID + "\",\"";
  10.     // Here we compute the sizeString
  11.  
  12.     var kids = curTable.getChildren();
  13.     var defaultPercent = Math.floor(100/kids.size())+"% "; // You have to love flexi data types
  14.  
  15.     for (var x in kids) {
  16.         var styleCandidate = x.style;
  17.         if (styleCandidate == null) {
  18.             result += defaultPercent;
  19.         } else {
  20.             var candidate2 = extractWidthFromStyle(styleCandidate);
  21.             if (candidate2 == "") {
  22.                 result += defaultPercent;
  23.             } else {
  24.                 result += candidate2;
  25.             }
  26.         }  
  27.        
  28.         result += " ";
  29.        
  30.     }
  31.  
  32.     result += "\",\""+tablewidth+"\");";
  33.     return result;
  34. }
  35.  
  36. function extractWidthFromStyle(styleCandidate) {
  37.     var result = "";
  38.     var whereisWidth = styleCandidate.indexOf("width:");
  39.     if (whereisWidth < 0) {
  40.         result = "";
  41.     } else {
  42.         var workString = styleCandidate.substr(whereisWidth+6);
  43.         var hasSemiColon = workString.indexOf(";");
  44.             if (hasSemiColon < 0) {
  45.                 result = workString;
  46.             } else {
  47.                 result = workString.substr(0,hasSemiColon);
  48.             }
  49.     }
  50.     return result;         
  51. }
The Client Side JS:
  1. function fixCatTableWidth(tableID, sizeString, tableSize) {        
  2.     // Reset the outer table width
  3.     var outer = dojo.byId(tableID+"_OUTER_TABLE");
  4.     if (tableSize == null || tableSize == "") {
  5.         outer.style.width = "100%";
  6.     } else {
  7.         outer.style.width = tableSize;
  8.     }  
  9.     var newWidth = sizeString.split(" ");
  10.     var max = newWidth.length;
  11.     // Get the table and all header elements
  12.     var table = dojo.byId(tableID);
  13.     var allHeaders = table.getElementsByTagName("th");
  14.     var maxHeaders = allHeaders.length;
  15.     for (i=0;i<maxHeaders;i++) {
  16.         var curWidth = (i > max) ? newWidth[max] : newWidth[i];
  17.         allHeaders[i].style.width = curWidth;
  18.     }
  19. }
As usual: YMMV

Comments

Gravatar Image1 - Stephan,

Could you post an example of how to append a button column to the end of a view. What I am aiming to achieve is to add a button to the end of every view row that lets users delete the document.

Cheers,
Wayne

Gravatar Image2 - I have followed the instructions as mentioned. But it doesn't seem to work. What could be the issue? I have two category columns and I am working on 8.5.1

Gravatar Image3 - @Sanjeet: what do you expect to happen, what did happen and what happens on a current version? I don't code for older versions

Gravatar Image4 - @Sanjeet: what do you expect to happen, what did happen and what happens on a current version? I don't code for older versions

Gravatar Image5 - Hi Stephan,

Thanks for the workaround.

For a categorized view not containing totals, I have been able to resolve the jumpy behavior by carefully setting XPages viewpanel & viewcolumn properties as follows
1. Set viewpanel width to a 100%
2. Do not specify any width for the view column headers and set the disableTheme property to true
3. Specify the width for ALL view columns in percent so that the total adds up to 100%
4. Care needs to be taken so that width does not fall below the minimum needed to display contents (eg. icon/checkbox)
5. For categorized & view icon columns, set disableTheme to true for allowing width to be reduced as per need
6. For categorized columns, set white-space:nowrap in the style attributes to prevent wrapping of categories
The only problem here is that view icons do not display if width is specified for the concerned column. But for view icon columns, if I specify width as required in step 4 and then remove it, things seem to work fine. This method seems to be working in IE7 & 8 with most view display requirements at our end. It can also be adapted for total width other than 100% (or fixed width in pixels, etc) as long as the sum total of individual column widths adds up to the total width of the view panel. Would appreciate your expert opinion on whether there could be any loopholes where this method should fail.

My main problem was for categorized views with totals, where XPages does not seem to span the category values across columns, thus disturbing column width settings. Though the JS workaround did not work directly, I was able to apply the technique described to check which of the view columns are categorized (in SSJS), loop thru all view data rows, change their colspan as needed and remove interim columns (in CSJS).

Not sure if these workarounds are ready (in terms of different environments, browsers, etc) to be posted for re-use but in tandem they should provide the final pieces for developers looking to build Notes-client like views in XPages with exactly matching look-n-feel

Thanks again

Gravatar Image6 - Setting the view panel parameters doesn't work for all browsers, so that's what this code is all about.
Views with Totals are a little more tricky. It can be solved. However you need to be very careful what you wish for (You might just get it). Your guideline for UI should not be "must look like Notes" - we had that in the R5 days. It better be "a modern web UI". There is a very good guideline available from IBM called the IBM OneUI. Looking at it I can't find a categorized view there. Going back to my original suggestions how to handle categorized views I can see the need for breadcrumbs, Tree controls, TableGrids or eventually a Dojo TreeGrid (check the original example). You would need to create a custom control once and then use that instead of the view control. There are also some very interesting things coming in 8.5.2 - but that's a story for another day.

As usual: YMMV

Post A Comment

Please note: Comments without a valid and working eMail address will be removed. This is my site, so I decide what stays here and what goes.

:-D:-o:-p:-x:-(:-):-\:angry::cool::cry::emb::grin::huh::laugh::rolleyes:;-)

Disclaimer

This site is in no way affiliated, endorsed, sanctioned, supported, nor enlightened by Lotus Software nor IBM Corporation. I may be an employee, but the opinions, theories, facts, etc. presented here are my own and are in now way given in any official capacity. In short, these are my words and this is my site, not IBM's - and don't even begin to think otherwise. (Disclaimer shamelessly plugged from Rocky Oliver)
© 2003 - 2014 Stephan H. Wissel - some rights reserved as listed here: Creative Commons License
Unless otherwise labeled by its originating author, the content found on this site is made available under the terms of an Attribution/NonCommercial/ShareAlike Creative Commons License, with the exception that no rights are granted -- since they are not mine to grant -- in any logo, graphic design, trademarks or trade names of any type. Code samples and code downloads on this site are, unless otherwise labeled, made available under an Apache 2.0 license. Other license models are available on written request and written confirmation.