06/15/2009

XPages Tip : Loaded Vs Rendered

Tags : XPages Lotus Development
6
Bookmark : del.icio.us  Technorati  Digg This  Add To Furl  Add To YahooMyWeb  Add To Reddit  Add To NewsVine 

In XPages when you look at the properties of any control there are options for 'Loaded' and 'Rendered'

A picture named M2

The difference is very subtle, while either of the properties will result in the control not displaying on the XPage if they evaluate to false there are times where the 'Loaded' property will result in a faster page for the end user. Here's an example...

In my Advanced XPages : A Nicer Domino Login Part 1 mini-series I have a custom control that included a number of Dojo libraries, some extra JavaScript and a Dojo dialog box. This code is only needed if the user of the site is not logged in so why bother load it once the user is logged in?

As I have everything inside a custom control I can set the 'loaded' or 'rendered' property on the page where I have added the custom control. If I use the 'rendered' property then the XPages processor still processes the custom control and even if the rendered property evaluates to false the XPages processor will detect that there are dojo libraries and extra resources to be loaded and will therefore insert them into the html header of the generated page.

If you use the 'Loaded' property and it evaluates to false the XPages processor will completely skip processing the control and therefore the extra dojo libraries and resources are not inserted into the html header and the resulting web page does not have any extra deadweight so the page will load slightly faster.

So if you have a reason to load extra resources in an XPage but only for special circumstances then consider putting them into a custom control and use the 'loaded' property so that they are only loaded when needed. Using this on my xTalk application I reduced the page load from a 155KB, 4.7 Second load time to a 92KB, 1.2 Second load time  ( with cache disabled ).

06/11/2009

Announcing xTalk the XPages Bulletin Board style Discussion Database

Tags : XPages Domino Discussion
9.37499999999999
Bookmark : del.icio.us  Technorati  Digg This  Add To Furl  Add To YahooMyWeb  Add To Reddit  Add To NewsVine 

The discussion database in IBM Lotus Domino has been around for a very long time getting minor updates as different versions of Domino came out over the years, mostly just color updates. When Domino 8.5 was released the discussion database design was given a major overhaul with a nice new XPages interface and for the future there may be even more changes with the news from OpenNTF that IBM may be looking at open sourcing the template.

IBM is considering open sourcing the discussion template, which would allow the community to extend it. IBM could then take the extensions back into the product.


Personally I've never been a big fan of the discussion template, mainy due to the way it does threaded replies. When doing threaded replies ( and replies to replies ) there are two ways to display them, either just display one reply at a time and show the subject lines of the threads below, very similar to how the forums on notes.net currently work, or you can try display all the entries on screen at the same time and indent the replies, only problem with this is with an active forum with lots of replies to replies you end up with entries displaying in about one inch on the side of the screen.

My prefered discussion forum format is the Bulletin Board style where all the replies to a topic appear directly below the main topic entry. This format is mainly used in forum software like phpBB or VBulletin and even the most excellent DomBulletin that you can currently get on OpenNTF in the projects section.

So I decided to write a phpBB Bulletin Board style XPages application TWO days ago. I start with a blank database, pulled in my base oneUI custom control layout design documents, created FOUR forms with about SIX fields on each one, created FOUR views and FOUR XPages containing the custom controls for the layout and one of FOUR custom controls on each XPage to display the contents for that XPage and I came up with xTalk.

You can try it out here : http://www.qtzar.com/openntf/xtalk/xtalk.nsf

I've granted anonymous access the ability to create new topics and reply to existing topics however in a production environment a login would be required to capture the name of the person posting to the forum.

There's still a few things to do, add sticky entries, grant the owner the ability to lock threads or forums and a little more CSS work to tidy things up. Hopefully once it's all finished I'll be able to release it on OpenNTF and who knows, maybe there will be two discussion databases in the next Domino release, one for threaded style and one for bulletin board style.

05/27/2009

XPages Calendar Control In A Table

Tags : XPages Calendar
0
Bookmark : del.icio.us  Technorati  Digg This  Add To Furl  Add To YahooMyWeb  Add To Reddit  Add To NewsVine 

In my last blog entry I showed how it was possible to build a calendar using a couple of repeat controls and some CSS but in reality a calendar is more suited to be displayed as a table. By using a table your calendar will also degrade nicely in older web browsers so I decided to give it a shot and see if it was possible to do in XPages.

The basic concept is still the same. I need to know how many days there are in the month and I need to know what day to start the first calendar entry on. Because I'm using a table I will also need to complete the last row of table columns with blank entries so this means I will need another repeat control.

In the CSS version of the calendar I assigned the first day of each week a slightly different style so that it would ensure that the row would move down. In a table I will need to close a table row tag and open a new one. At first I tried to just add a </xp:tr> and a <xp:tr> tag into the main repeat and set their 'rendered' value so that they would only render on the first day of each week but Domino Designer would not allow me to do this because you cannot add a 'rendered' value to a closing tag, only the opening tag.

To get around this I decided to just fool the xpages rendering engine to output the closing and reopening table row tags by using a computed field that is set to send it's results to the web browser as html.

A picture named M2

This worked perfectly, before the repeat control outputs the first table column of the week and closing tag for the previous table row and then an opening tag for the next table row is sent to the browser.

The last thing I needed to do was add an extra repeat to fill out the blank table columns at the end of the last row and then I needed to close the final table row before closing the entire table. The maximum number of rows that a calendar might take is 6, this means that your calendar table must have at least 42 table columns split over the 6 rows. You already know the number of blanks at the start of the table and the number of days in the month so subtracting these from 42 will give you the number of blanks at the end of the table.

Of course it's entirely possible for a calendar month to only need 4 rows, as was the case in February this year where the first of the month was a Sunday and the 28th of the month was a Saturday so we need to check the result of our calculation to remove any blank rows by subtracting either 14 or 7 as necessary.

A picture named M3

Now we just need to apply a little CSS just for the table and we have a working calendar control in XPages based on a table.

A picture named M4

05/26/2009

Building an XPages Calendar Custom Control

Tags : XPages Calendar
0
Bookmark : del.icio.us  Technorati  Digg This  Add To Furl  Add To YahooMyWeb  Add To Reddit  Add To NewsVine 

If you read my blog directly on my site and not through a RSS reader then you may have seen the nifty calendar that I wrote in BlogSphere. It's AJAX based and allows the reader to move backwards and forwards through the different months to see what other days have blog entries.

A picture named M2

I wanted to recreate something very similar in XPages and started looking at a few options. The blogsphere version is a table which makes sense as it really is tabulated data but after thinking of a few ways to do it in XPages I decided to move to a pure CSS generated calendar. Each of the little squares in the calendar is a simple SPAN and the CSS is used to give them a border, float them to the left so they all line up after each other and then a surrounding DIV forces them to wrap around.

The header for the calendar is defined as simply as


<xp:span styleClass="calHeader">S</xp:span>
<xp:span styleClass="calHeader">M</xp:span>
<xp:span styleClass="calHeader">T</xp:span>
<xp:span styleClass="calHeader">W</xp:span>
<xp:span styleClass="calHeader">T</xp:span>
<xp:span styleClass="calHeader">F</xp:span>
<xp:span styleClass="calHeader">S</xp:span>



The next set of spans are the empty cells at the start of the calendar. Before I create the empty cells for the calendar I need to figure out how many there will be so I need a bit of server side javascript.


viewScope.dispCalYear = @Year(@Now());
viewScope.dispCalMonth = @Month(@Now());
viewScope.daysInMonth = new Date(viewScope.dispCalYear, viewScope.dispCalMonth, 0).getDate();
viewScope.firstDayInMonth = new Date(viewScope.dispCalYear,viewScope.dispCalMonth -1 ,1).getDay();


Here I get the current year and month. The number of days in the month is calculated by getting day zero of next month. JavaScript sees the request for day zero of a month as being a request for the last day of the previous month. It is a great shortcut because you don't need to worry about calculating leapyears, the javascript processor does all that for you. In javascript January is defined as 0 but in @formula language January is defined as 1. This explains why I don't need to add one to the month.

To get the first day in the month I pass in the 1st of the current month ( hence the -1 on the month variable ) and call the getDay function. This returns a 0 for Sunday, 1 for Monday and so on. If your doing a European style calendar where Monday is the first day on the left make sure you adjust the value returned here as required.

The number that we got back for the first day in the month is also the number of blank entries we need to pad the calendar with. To do this in XPages we can use a very simple repeat control. Repeat controls don't need to be linked to Domino data sources. In this case I'm setting the repeat's source as an integer and the repeat will repeat that many times. Inside the repeat control I just have a blank span.

<xp:repeat id="calBlanks" rows="7" value="#{javascript:viewScope.firstDayInMonth}" var="calblankVar">
<xp:span styleClass="calBlank" />
</xp:repeat>


Being able to do a repeat based on an integer also makes generating the actual calendar spans very easy also. We already have the number of days in the month thanks to the zero day trick explained above.


<xp:repeat id="repeat1" rows="31" value="#{javascript:viewScope.daysInMonth}" IndexVar="calIndex" var="calVar">
<xp:text escape="true" id="computedField1" value="#{javascript:calVar + 1}">
<xp:this.styleClass><!DATA[#{javascript:if (calIndex != 0){
       if (calIndex + firstDayInMonth  % 7 == 0){
       return "firstday";
} else {
       return "";
} } }>

</xp:this.styleClass>
<xp:this.converter>
<xp:convertNumber type="number" integerOnly="true" />
</xp:this.converter>
</xp:text>
</xp:repeat>



Make sure the repeats max is set to 31 ( the default is 30 and you'll wonder why certain months don't show that 31st day if you forget to change the default ). Inside my repeat I have a computed field set to display the repeats index plus one ( the index starts at zero ). I am also calculating the style class so that every eight span ( including the blank spans ) has a special css class assigned to it that ensures the row moves down to the next next row of the calendar.

We now have a very simple calendar in XPages. With some extra coding you can add some forward and backwards links above the calendar that will add or subtract one to the viewScope month/year variable and then do a partial update of the panel containing the calendar. Here's what my final calendar looks like with the extra coding completed.

A picture named M3

As you can see I have also redone my calendar CSS so that it blends in well with the oneUI scheme.

05/19/2009

Advanced XPages : Debugging Scoped Variables

Tags : XPages Scope Debug
0
Bookmark : del.icio.us  Technorati  Digg This  Add To Furl  Add To YahooMyWeb  Add To Reddit  Add To NewsVine 

Probably one of the most useful features in XPages has to be the scope variables, with proper planning you can really make good use of them and eliminate the need to store temporary values in backend notes documents. As I showed in a recent blog entry you can put anything into a scope variable, including a hashmap and you can then run a repeat control off the hashmap. Well the scope variables themselves are also hashmaps so why not use the same technique to see what's in them.

There are four scope variables that you can use, applicationScope, sessionScope, requestScope and viewScope. To make it easier to debug an application that is using scoped variables I have created four new custom controls, one for each of the four scoped variables. The code in the custom controls is simple.

<?xml version="1.0" encoding="UTF-8"?>
<xp:view xmlns:xp="http://www.ibm.com/xsp/core">
<xp:panel id="applicationVars" styleClass="debugPanel">
<xp:table styleClass="debug">
<xp:tr>
<th>Variable Name</th>
<th>Variable Content</th>
</xp:tr>
<xp:repeat id="varRepeat" rows="30" value="#{javascript:applicationScope.keySet();}" var="scopeData">
<xp:tr>
<xp:td>
<xp:text escape="true" id="varName" value="#{javascript:scopeData}" />
</xp:td>
<xp:td>
<xp:text escape="true" id="varValue" value="#{javascript:applicationScope.get(scopeData)}" />
</xp:td>
</xp:tr>
</xp:repeat>
</xp:table>
</xp:panel>
</xp:view>


For the other custom controls you just need to replace applicationScope with the other scope variables.

Using your new custom controls is easy, just add them to the bottom of any page where you need to keep an eye on the scoped variables. If your only using the sessionScope on a page then you just need to add that custom control, if your making use of the requestScope then just include that custom control.

I also like to create a new xPage in my applications called 'debug' where I put in the custom controls for the application and session scopes for easy access to them.

Don't forget to remove ( or hide ) the debug info before releasing your application.

05/18/2009

XPages for iPhone

Tags : XPages iPhone
6.79999999999999
Bookmark : del.icio.us  Technorati  Digg This  Add To Furl  Add To YahooMyWeb  Add To Reddit  Add To NewsVine 

Well kinda....

Developing a web application for the iPhone or any mobile browser is a bit different from developing for a desktop browser. You need to take into account the size of the screen, the amount of css file external JavaScript files that are downloaded and, in the case of the iPhone, you may even want to get your application to conform to the Apple iPhone Web User Interface guidelines.

If your developing an XPages application you could just leave it as is and quite a lot of your application will work on the iPhone. It will look exactly like it does on the desktop web browser but a lot smaller. The dojo stuff seems to work ok so far, even partial refreshes seem to work but there is a lot more you could do for your iPhone users.

Lets start by redirecting your iPhone users to a different page that might be customized for the iPhone. This is actually pretty simple. In the beforePageLoads event for the page you want to redirect FROM you can put in the following serverside JavaScript :

var uAgent = context.getUserAgent().getUserAgent();

if (uAgent.match("iPhone") != null){
       context.redirectToPage("/iPhone.xsp");
}


By looking at the userAgent string provided by the users browser we can quickly redirect to a different page. Nice and simple.

If your application is using a theme document then you could also make sure that a special iPhone CSS file is loaded, for example

<resource rendered="#{javascript:context.getUserAgent().getUserAgent().match("iPhone")}">
<content-type>text/css</content-type>
<href>iPhone.css</href>
</resource>


Adding a similar but reversed rendering command to the rest of your css files in the theme document would make sure that those css files are not loaded when using the iPhone.

Obviously the same concepts will work for any browser, mobile or desktop. So who knows maybe soon we'll start seeing Xpage applications that contain multiple interfaces based on the browser that is accessing them.  I know I'm going to work on an iPhone interface for the XPages Phonebook, who knows maybe there will be another short tutorial on how I build it.

05/15/2009

xPages Workshop at Workflow Studios, Dallas, May 20th

Tags : XPages Training
0
Bookmark : del.icio.us  Technorati  Digg This  Add To Furl  Add To YahooMyWeb  Add To Reddit  Add To NewsVine 

Workflow Studios is sponsoring a special FREE workshop on developing IBM Lotus Domino web applications using XPages on May 20th in their Dallas office. It is going to be based around the 'Learning XPages' blog series that I wrote and who better to give the workshop then the person who wrote it..

That's right, I'll be in Dallas as a special guest of Workflow Studios to give the workshop and I'm really looking forward to it. While I won't be able to cover every single detail we will be following along the 'Learning XPages' tutorial as closely as possible with a couple of extras thrown in that I have learnt since writing the blog series.

So if your in the Dallas area and want to learn about XPages then please join us. Registration is still open.

05/12/2009

Is OpenNTF In Danger Of Jumping The Shark

Tags : OpenNTF
7.32499999999999
Bookmark : del.icio.us  Technorati  Digg This  Add To Furl  Add To YahooMyWeb  Add To Reddit  Add To NewsVine 

Back in January at Lotusphere there was a huge cheer when, during the opening general session, it was announced that IBM would be providing some resources to and partnering with OpenNTF. It is something that many in the notes community, especially those who have active projects on OpenNTF have been vocal about in the past and the announcement looked like IBM were going to listen to what the people wanted and help out.

Todays announcement and OpenNTF redesign, however, makes me feel that OpenNTF has lost some of it's roots and is dangerously close to heading in the wrong direction and alienating the very developers that made it successful.

I like the idea of the catalog of high quality applications but right now it just contains IBM projects. There are plenty of other OpenNTF projects that deserved to be in the catalog from day one including, but not limited to, the OpenNTF Mail Experience, !!HELP!!, Vacation Requests, OpenLog and even my own BlogSphere project. Right now all I am seeing is self promotion of IBM projects. This is something that needs to be rectified quickly before people visiting the site just see if as a repository for IBM sanctioned templates.

And what exactly is OpenNTF all about, well in my mind the main reason for OpenNTF are the different projects but they seem to have taken a back seat to the catalog, yes there are plenty of 'half finished' projects in there, they need to be weeded out but definitely not forgotten about. Some of those projects contain some great code that could help somebody out. The active projects need to be brought back out to the homepage for the site, not just the list of catalog items. These are the guts of OpenNTF and the projects are what made OpenNTF work. Hopefully somebody somewhere is working on a redesign of this area and will incorporate all the ideas that have been mentioned in the IdeaJam area.

My biggest issue however is the red tape that has sprung up. If I want to 'commit' new code for something like BlogSphere I'm first going to have to get written consent from my employer. If anybody out there wants to contribute some code for Blogsphere to me then I'm going to have to do my own due diligence to make sure that your authorized by your employer to submit the code and that you in fact own the code your submitting to me. I know this is all cover your backside sort of stuff but this sort of change should have been discussed with ALL the current project owners on OpenNTF.

And lets not forget the license, No more using any license other the Apache Public License V2 except with express permission of the new steering committee. Not not all open source licenses are the same. Did you know that under the Apache V2 license anybody can take your code from OpenNTF, make modifications and then patent their changes and sell the modified code as part of their products as long as they include the attributions and original license document, whereas GPL or LGPL states that they can only distribute the modified work if the distribution is also a GPL'd or LGPL'd. My take on this is that by forcing the Apache license IBM can then selectively include certain templates from OpenNTF in the next release of Notes/Domino if they meet certain standards. How would you feel if a business partner redistributed the top 50 projects on OpenNTF as 'The New Nifty Fifty' and made a profit on it. Is this something that project managers would like to see happen? IS the restriction of the Open Source license to APL V2 a good thing or a bad thing?

OpenNTF has been a great resource since it's conception, From it's humble beginnings as NotesOSS with a single project based on the mail template till today, OpenNTF has attracted some brilliant ideas and developers but all this could easily be lost if the new steering committee is not careful.

So I have one message to the members of the new steering committee... Don't forget who OpenNTF is for and what it's original purpose was. You are in a position of trust and you can either steer the site back onto a path of collaborative development or you can steer it over the edge of a cliff into obscurity and red tape. A group of 10 people in a steering committee does not make a website, it's the users of the site that make the difference.

-------------

And to any commenter who wants to say that if I don't like the changes I could just pull my projects from the site, I say this... Yes I could and who knows it might have to come to that, but there is a committee of 10 people, many of whom will see this blog entry and with luck many of them will read it, take the concerns on board and rectify what they can and get things back on track before they lose the heart of the developer community. I can only hope the steering committee are in this for the right reason and not just so they can advertise their corporate logos at the bottom on the OpenNTF website.

05/11/2009

Advanced XPages : Creating a custom 'No Documents Found' message

Tags : XPages getComponent Repeat
0
Bookmark : del.icio.us  Technorati  Digg This  Add To Furl  Add To YahooMyWeb  Add To Reddit  Add To NewsVine 

In traditional domino web development when you add a view to a webpage and there are no documents you would end up with a standard 'No Documents Found' message. In many cases as a developer you would would then apply a number of hacks to either replace or control the look and feel of this message.

In XPages we now have the concept of view panels or repeats to list all the documents in a view and for the most time you will use these types of controls with a pager control to allow the user of your application to go back and forth through different pages in the view.  This is a vast improvement on traditional domino web development but it does bring up one new issue, what if the view has no documents, do you even want the pager to display?  In the phonebook application I created for the Learning XPages series my pager had a 'Page 1 of x' section, on a view with no documents that appears as 'Page 1 of 0' which is just wrong so I wanted to hide the pager and instead display a friendly message to the user.

To hide the pager I needed to set it's rendered' property to a computed value. I decided to look at the row count for the repeat that I was using on the page and check to see if it was zero. If it was zero then I would hide the page and if not then I would show the pager. I decided to use the row count for the repeat control instead of the row count for the data source because if you are using filters on the data source then the row count for the repeat control is the number of rows AFTER the filter is applied whereas the row count for the data source is the number of rows BEFORE the filter is applied.

Here's the code that I used for the pagers render script in a simplified/expanded form :

var testValue = getComponent("itemListRepeat");
if (testValue.getRowCount() == 0 ){
       return false;
} else{
       return true;
}


If you want to create a customized message to display to the end user you can simply create a new panel control that contains your message and apply the exact same rendered formula expect switch the true and false statements. You can also apply a special styleclass to the new panel to help make it stand out. If your using the oneUI you could use 'lotusMessage' to make it look like this :

A picture named M2

One interesting thing that I found is that you can hide the panel containing the repeat control using the exact same formula. Even though the repeat control is inside the panel that your hiding it's row count is available to check before the page is rendered. I'm not sure if this is intentional or not so if you do hide the entire repeat panel as well any pagers linked the repeat make sure you test this in future versions.

05/08/2009

Advanced XPages : Extending the sessionScope to store a hashmap

Tags : XPages Lotus Domino SessionScope Hashmap
0
Bookmark : del.icio.us  Technorati  Digg This  Add To Furl  Add To YahooMyWeb  Add To Reddit  Add To NewsVine 

I've been busy working away on a new XPages application in work that implements a typical shopping cart like you might find on Amazon or other online retail websites. When I started planning the application I hit upon the idea of storing the items that the user had added to the shopping cart into a variable in the sessionScope. The sessionScope, in xPages, is an area of memory that you can store values for use by server side javascript in your application. Each user who logs into the application has their own sessionScope as opposed to the applicationScope that is shared across all users of the xPages application. My idea was that by using the session scope I wouldn't have to create any temporary backend documents to store the selected items.

Normally you put stuff into the sessionScope using the 'put' method, for example sessionScope.put("userFirstName","Declan"). You can also write this in shorthand as sessionScope.userFirstName = "Declan". To get stuff out of the sessionScope you use the get method, for example sessionScope.get("userFirstName") or in shorthand sessionScope.userFirstName

In javascript you can store anything inside a variable including another object. Based on the 'Namespacing Scoped Variables' blog entry by Tim Tripcony I figured that I'd be able to use my sessionScope to store an array of Unique ID's and their quantities. After talking with Tim about the idea he suggested that I put a hashmap object into my variable in the sessionScope.

To initialize the variable I'm using the following line of code.

sessionScope.cartItems = (sessionScope.cartItems || new java.util.HashMap());


This sets the sessionScope.cartItems to be equal to itself so that I don't accidentally clear it's value, however if sessionScope.cartItems does not exist yet then the second half of the statement is carried out which created the HashMap object in the sessionScope.

Now that I have a hashmap inside the sessionScope I can use all the methods on it as I would the sessionScope

var thisDocID = currentDocument.getDocument().getUniversalID();
var thisQuantity = getComponent("comboBox1").getValue();
sessionScope.cartItems.put(thisDocID,thisQuantity)


By using the UNID as the key I can easily relate the item in the cart back to the item documents in my notes database. I can even use a repeat control bound to sessionScope.cartItems.keySet(); loop through all the items in the shopping cart. I could use sessionScope.cartItems.size(); to find out how many items are in the shopping cart and even sessionScope.cartItems.clear(); to empty the cart out.

Hopefully knowing that you can store different types of objects in the sessionScope will give you some ideas for your own applications.

Dec's Dom Blog

Domino 7 OpenNTF BlogSphere LotusGeek Login RSS Feed

PlanetLotus