x$ – now a part of XPages Extension Library

I am very flattered to find out that not only is my x$ OpenNTF xSnippet being used more widely than I realized (over 600 downloads). It now being used in the latest release of the OpenNTF Extension library.

If you look here – http://bootstrap4xpages.com/xsp/.ibmxspres/.extlib/responsive/xpages/js/xsp-mixin.js and search for it you will find


//jQuery selector that works with XPages IDs
//See - http://openntf.org/XSnippets.nsf/snippet.xsp?id=x-jquery-selector-for-xpages
function x$(idTag, param){
	idTag = idTag.replace(/:/gi, "\\:") + (param ? param : "");
	return($("#" + idTag));
}

Who knew my first foray into the XPages community would have such an impact.

The lesson here boys and girls should be that you should *share* your work however small and insignificant you think it is. Like all scientific research, very little code is “a completely new way of doing things”. Generally everything grows incrementally and just because you don’t think something is significant, someone else might.

You are reading this – what have you shared recently?

🙂

 

Searching XPages REST service and returning the real count in the results.

In this article I will show you how I managed to get the search results count into a REST service and why I wanted to do that.

Introduction

Back in August 2012 I posted this on Stackoverflow. I will answer the question there but I don’t feel like I have “answered” it, just worked around it.

How do I make the XPages REST control return the overall number of filtered matches?

http://stackoverflow.com/questions/11786930/how-do-i-make-the-xpages-rest-control-return-the-overall-number-of-filtered-matc

Problem

When you create a viewItemFileService REST service using the the ExtensionLibrary control you get a response which looks like this:

{
    "@timestamp":"2013-03-12T23:25:57Z",
    "@toplevelentries":1299,
    "items":
    [
      {
          "@entryid":"100-8DE5EBF5E35C17F285257B1B00254A8F",
          "@unid":"8DE5EBF5E35C17F285257B1B00254A8F",
          "firstname":"Benjamin",
          "lastname":"Imran",
          "address":"2112 Hall Street",
          "city":"Las Vegas",
          "state":"NV",
          "zip":89121,
          "country":"US",
          "email":"Benjamin.A.Wayman@mailinator.com"
      },

which is fine…and from that you can ascertain that there are 1299 documents in the view (@toplevelentries)

The problem is when you execute a search against this REST service (for example ‘[address] contains street’) you still get @toplevelentries: 1299

This causes me great angst when it comes to the EXTJS grids because I want to use the Infinite Scrolling capability. What that does is calculates based on the size of the view (1299) how large a scroll bar to create and then display 25 entries at a time and load them as necessary. This is really smart except after you have searched the REST service. The grid still thinks there are 1299 documents even when there is only a subset matching the search results. This causes a lot of blank scrolling 😦

In my example the search ‘[address] contains street’ returns 338 matches. But this causes the following to happen with the infinite grid

rest1

And that sucks. Also note 52 pages in the pager!!!!

The EXTJS code to get the number of documents in the service looks like this:

 var store = Ext.create('Ext.data.Store', {
        // allow the grid to interact with the paging scroller by buffering
        buffered: true,
        pageSize: 25,
        leadingBufferZone: 25,
        autoLoad: true,
        autoDestroy: true,
        autoSync: true,
        model: 'Person',
        proxy: {
            type: 'rest',
            url: 'xRestService3.xsp/marky?count=25',
            reader: {
                type: 'json',
                root: 'items',
                totalProperty : '@toplevelentries' // This is the determining value
            },
            writer: {
                type: 'json'
            }
        }
    });

And as you can see form the code @toplevelentries is always 1299

So how do we get the 338 number to the grid without causing:

  • Some major hacktastic, back end to front end, extra ajax calls, and  redrawing the grid on the fly shenanigans
  • Manually re-writting the REST service from scratch (which I could do but would cause much pain and suffering)
  • Performance issues with XPiNC connecting to the server
  • My eyes to bleed…..

This has baffled me for months and here’s how I got around it.

Solution

In the REST service you can create a custom column. In this case we are just returning the requestScope value for markyCount in the column “theRealCount”:

<xe:this.columns>
	<xe:restViewColumn name="theRealCount">
		<xe:this.value>
		<![CDATA[#{javascript: return requestScope.get("markyCount")}]]>
		</xe:this.value>
	</xe:restViewColumn>
</xe:this.columns>

And markyCount is going to be the 338 value from the search. So how do we get that?

The REST service has an id value which can be computed – and I really don’t care what the id is because I am not binding it to a control on the form. So I used the opportunity for some server side computation of the id to create a little FTSearch.

In the example below I am simply getting the view used by the REST service (byFirstName) doing an FTsearch on it and then putting the count in the markyCount requestScope.

<xe:this.id>
	<![CDATA[${javascript:
		var theView:NotesView = database.getView("byFirstName")
		var count = theView.FTSearch("[address] contains street");
		requestScope.put("markyCount", count)
		return "searchMe" //irrelevant value
		}
	]]>
</xe:this.id>

So what this does is create a REST service output which looks like this:

{
    "@timestamp":"2013-03-12T23:25:57Z",
    "@toplevelentries":1299,
    "items":
    [
      {
          "@entryid":"100-8DE5EBF5E35C17F285257B1B00254A8F",
          "@unid":"8DE5EBF5E35C17F285257B1B00254A8F",
          "firstname":"Benjamin",
          "lastname":"Imran",
          "address":"2112 Hall Street",
          "city":"Las Vegas",
          "state":"NV",
          "zip":89121,
          "country":"US",
          "email":"Benjamin.A.Wayman@mailinator.com",
          "theRealCount": 338  //this is the new column
      },

Note theRealCount column with 338 in it. This is then added to every column output by the REST service. So yes the downside is that we are adding computation and output data size to the feed but it appears to make an insignificant amount of difference to the output speed of the service.

We then change the EXTJS code to look at the theRealCount value in the first Item and not @toplevelentries

 var store = Ext.create('Ext.data.Store', {
        // allow the grid to interact with the paging scroller by buffering
        buffered: true,
        pageSize: 25,
        leadingBufferZone: 25,
        autoLoad: true,
        autoDestroy: true,
        autoSync: true,
        model: 'Person',
        proxy: {
            type: 'rest',
            url: 'xRestService3.xsp/marky?count=25',
            reader: {
                type: 'json',
                root: 'items',
                totalProperty : 'items[0].theRealCount' // This is the determining value
            },
            writer: {
                type: 'json'
            }
        }
    });

And we get this – no more blank lines and 14 pages in the pager 🙂

rest2

XPages SSJS: Beware – context.getURL() does not do what it says on the tin!

In working with the EXTJS grids I recently noticed an issue with the way I was getting the URL submitted to a REST service. The intention was to ready the query_string parameters created by the EXTJS grid filters, turn them into a notes understandable search string format and query the REST service. Seemed simple enough……

So to get the query_string initially I used context.getUrl() in the search property of the REST service. This returned the following when printed to the console (I have added carriage returns for clarity).

The important thing to look for is the filter[0][data][value]

print(context.getUrl().toString())

03/04/2013 12:36:20 PM HTTP JVM:
count=25&keys&_dc=1362420087840
&filter[0][field]=txtStatus
&filter[0][data][type]=list
&filter[0][data][value]=Sent
&page=1&start=0&limit=25&sort=GKO_DateLastMod&dir=DESC

The problem is that that was not the URL calling the REST service. The URL actually contains two parameters which are the same, but have different values.

…thedatabase.nsf/xRestService.xsp?count=25&keys=&_dc=1362420087840
&filter[0][field]=txtStatus
&filter[0][data][type]=list
&filter[0][data][value]=Draft
&filter[0][data][value]=Sent
&page=1&start=0&limit=25&sort=GKO_DateLastMod&dir=DESC

It would appear that the XSPContext object was somehow unique-ing the incoming parameters and losing the first one. Mild panic ensued and then I quickly realized there was another way to get the URL string using the facesContext…..(thanks to Julian Buss for the code)

var urlstring = facesContext.getExternalContext().getRequest().getQueryString()
var resultstring=java.net.URLDecoder.decode(urlstring,"UTF-8");
print(resultstring)

03/04/2013 12:36:20 PM HTTP JVM:
…thedatabase.nsf/xRestService.xsp?count=25&keys=&_dc=1362420087840
&filter[0][field]=txtStatus
&filter[0][data][type]=list
&filter[0][data][value]=Draft
&filter[0][data][value]=Sent
&page=1&start=0&limit=25&sort=GKO_DateLastMod&dir=DESC

This gave me the full string I was looking for which I was then able to conquer the world with (well OK the REST service anyway)

In Summary

using context.getUrl() on a URL with query_string that looks like this

&filter[0][data][type]=list&filter[0][data][value]=Draft&filter[0][data][value]=Sent

returned this which is wrong

&filter[0][data][type]=list&filter[0][data][value]=Sent

Don’t use: context.getUrl() to get the URL + Query_String
Use: facesContext.getExternalContext().getRequest().getQueryString()

Searching a REST service – when the default is not everything

I have wasted too much time over the last couple of days figuring out why my REST service will only return 32 entries….

Problem
This would seam like a simple search using the viewJSONService and I would expect in my case to see 198 results

<xe:restService id="marky" pathInfo="marky">
	<xe:this.service>
		<xe:viewJsonService defaultColumns="true" viewName="ByName-First">
			<xe:this.search><![CDATA["Avenue"]]></xe:this.search>
		</xe:viewJsonService>
	</xe:this.service>
</xe:restService>

But I only get 32 – why???

Solution

Something simple, small and unassuming – searchMaxDocs. When it is not set the default is not All Matching Documents as I had assumed…

search1

If you do NOT set searchMaxDocs to ZERO you will never get more than 32 documents in your search results.

<xe:restService id="marky" pathInfo="marky">
	<xe:this.service>
		<xe:viewJsonService defaultColumns="true" viewName="ByName-First" searchMaxDocs="0">
			<xe:this.search><![CDATA["Avenue"]]></xe:this.search>
		</xe:viewJsonService>
	</xe:this.service>
</xe:restService>

Conclusion

The default number of results when searching a REST service is 32

Always set your searchMaxDocs=”0″

How to always show OneUI action buttons with a simple CSS trick

In this article I will show how your ExtLib Application Layout Control action buttons (OneUI) can remain on the page at all times with a simple CSS Trick.

The following was created using the Extension Library Application Layout control – with OneUI v2.1 using the silver theme.

Introduction

OneUI is a great, simple layout for a nice clean application layout without too much worry about CSS and other complicated design things. There are some nice examples on the OpenNTF site about using the OneUI layout. The http://xpages.info/XPagesHome.nsf/Home.xsp website uses the same layout and you can see for yourself how the top bars scroll out of the screen as you move down the page.

The buttons in the PlaceBar stay put as the page scrolls down – as the page gets larger this becomes more of a pain for the user to have to scroll back to the top to get to the Save button.

The desired effect

My requirement in modernizing my current R5 web based application was to keep the look and feel as close to the original frameset as possible. The buttons were in the top frame and therefore visible on the page at all times. Without wanting to revert back 15 years and use frames in the XPage I had to come up with a way to keep the buttons on the page at all times.

The initial look

The initial buttons look like this in the placebar – nothing spectacular to see here

Save and Cancel button
Save and Cancel button

 

Using what else – FireBug 

So I had to figure out first of all what the CSS was for the buttons and then if I could change them. Looking at the HTML in FireBug you can see that the buttons are in a DIV with two classes: .lotusPlaceBar and .lotusBtnContainer

Looking at the OneUI buttons in FireBug
Looking at the OneUI buttons in FireBug

 

Fixing the position

Fixing the position of the buttons is as simple as using “position: fixed” and then they stay in that place on the screen. I added some other styling to pad it a little, and move at away from the side of the screen like this

Fixing the button position
Fixing the button position

This is achieved by adding the following style to the XPage

		.lotusPlaceBar .lotusBtnContainer {
		    background: url("/xsp/.ibmxspres/dojoroot-1.6.1/dijit/themes/claro/images/titlebar.png") repeat scroll 0 0 #EEEEEE;
		    border: 1px solid #CCCCCC;
		    float: right;
		    padding-bottom: 0.3em;
		    padding-right: 0.3em;
		    padding-top: 0.3em;
		    position: fixed;
		    right: 20px;
		    z-index: 99999;
		}

There we have it – fixed buttons on the page

As you can see from the picture below – the buttons stay in exactly the same place on the screen as the user scrolls down the page

Buttons fixed in place
Buttons fixed in place

All the way to the bottom of the screen

All the way to the bottom
All the way to the bottom

Dynamic TabPanel height with Dojo TabContainer in XPages

In this article I will discuss how to make your Tab Panels dynamically resize to the size of their content. I will use the doLayout property of the dijit control, exposed through the extension library control properties in XPages Designer.

Introduction

The Extension Library provides us with many easy to use Dojo “containers” including the TabContainer and TabPanel. What is sometimes difficult to decifer though is how to configure the dojo container to bend to your will and meet your requirements.

The Problem

My problem was that I have a container with multiple tabs and some are really large and some are small. The out of box the box functionality provides the ability to size the TabContainer and it forces that size on all the panels. This leaves me with two options (see the demo):

  • Make all the boxes large enough to cover the largest panel
    • which looks daft on the panels with very little content
  • Make the overflow of the larger panels use a scroll bar
    • style=”overflow-y: auto”
    • This is “ok” but with a lot of scrolling it makes the panel difficult to use

The solution

So I was searching around Google and I could not find an answer to “dojo TabContainer dynamic resize” which was very frustrating – so I came upon the dojo documentation for the TabContainer. http://dojotoolkit.org/reference-guide/1.7/dijit/layout/TabContainer.html And experience has told me I am wasting my time with the Dojo documentation but I figured what the hey and clicked in……

Now I would rather stab my eyes out than read the dojo API documentation – but I have to hold my hand up and give them props for this one – it is right there in the demonstrations on the first page “A TabContainer with flexible height” – Brilliant!

The trick is to add doLayout=”false” to your dojo container – simple – and a working demonstration as well – well done sirs!!!

So then I went to the XPages designer to look and see if the property was there on the custom control – and yes it was – brilliant – and how absolutely 100% USELESS the help was for it……How is this helpful???

XPages designer help for the doLayout property of the TabContainer control
XPages designer help for the doLayout property of the TabContainer control

It would have been much more helpful to say “default=true – forces all the Tab Panels to be the same height as the TabContainer. Set to false to allow for flexible tab Panel height!”

The dojo API documentation says “If true, change the size of my currently displayed child to match my size” – written by closet programmers and not by real people, apparently.

Demo

Here is the simple demonstration of the difference – quite striking really

http://demo.xomino.com/xomino/xPlay.nsf/xTabContainer.xsp

Conclusion

Dojo reference guide actually helped………and I need to use it more often apparently.

(I still refuse to waste my time on the API documentation though)

The Moral

I think for me it is imperative to understand more about how the dojo containers work in their original environment – the CSJS library before attempting to use them in XPages. I realize this is contrary to the idea that we don’t “have” to understand them to use them in XPages – but actually – I now think it is essential

For more information check out the Dijit information – reference guide – real people speak!

http://dojotoolkit.org/reference-guide/1.7/dijit/info.html#dijit-info

XPages Extension Library Book – it just makes you better!

In this article I will review the new XPages Extension Library book by IBM Press.

Introduction

If you are using or going to use XPages in your organization you need to get the Extension Library – it is already included in 8.5.3 UP1 and in the future it is just going to be part of the standard install and we won’t even consider it an “add on”.

And if you are a developer using the Extension Library, like you should, then you NEED to buy this book and read it. I am not understating that fact, you need to buy it, otherwise you are doing yourself and your company a disservice. What I realized very quickly was that I thought I knew the Extension Library, when in fact I had only scratched the surface and how much more functionality I could be taking advantage of. I have used many parts of the Extension Library now for a few months and I have stolen re-used parts of the example database like the REST services and basically copied and pasted them. I never really understand what they were and how the worked, but didn’t need to either………my loss apparently.

So what’s it do for me?

It just makes you better – and unless you improve and get better, someone else’s going to be doing your job for you!

What this book does is it breaks down all those sections you see every day in the Control Palette and explains it in simple to understand manner.

Extension Library controls in your Designer Control Palette
Extension Library controls in your Designer Control Palette

For example…

  • Chapter 2 – Installation and deployment, written from the perspective of someone who’s had to do it, a LOT and you know they know what they are talking about.
  • Chapter 4 – Forms Dynamic Content and More contains a section on the Dynamic Content control – that is the equivalent of computed Subforms – who knew!! Excellent !!
  • Chapter 5 – Dojo made easy– this does an excellent job of explaining how dojo is integrated into the XPage designer client with good examples!!
    • and I still prefer jQuery, but now I have an even better understanding of why 🙂
  • Chapter 9 – The Application’s Layout has a history of OneUI and while I still think it is massively over complicated for what it needs to be, there are clear explanations of how it breaks down and how you can manipulate each separate section for your evil needs
  • Chapter 11 – REST services took my knowledge from 10% to 90% in an hour. Soooooo many applications for this capability, I *really* wish I had had this 10 years ago!
  • Chapter 12 – XPages gets relational – oh yes it does baby!
  • Chapter 13 – Get Social – I would love to get social and now I know how to – (but I am not social and will now go back in my corner and cry)

 

Talk to me like a person – not a machine

You know when you add an ExtLib custom control to your XPage and you see the “All Properties” and 95% of the explanation seems alien speak to you? This book provides the “real person” explanation of the property and what it does for you. Laying all the properties out together in one place also makes is a whole lot easier to understand the control, its purpose and how you use it!

details on client - que?
details on client – que?

Is really IBM speak for….

oooh that's what it means
oooh that’s what it means

 

The Authors

To varying levels I have gotten to know the authors of this book over the last few months and they a genuinely some of the best people you could ever hope to meet. They wrote this book because they are just like you and me – developers – and they want to spread their knowledge and make the whole community better.

Conclusion

This book was written by developers for developers and like I said, you owe it to yourself and your company to check it out. The cost of the book is less than an hour’s worth of your time to your company and unless you are an XPage ÜberGenius already, you cannot help but learn from this book and it will pay for itself the first day you really sit down and read it.

Go Buy it ! No buts, just go buy it.