Monday, November 18, 2013

Really Strange Behavior with the REST Service Control in Xpages

Today I encountered some really strange behavior when trying to add a new column to a view that is used by a REST service.  I couldn't find anything out there on this, so I decided to write a short blog post detailing what happened and how I fixed it.

I was wanting to add a new column to the underlining view that the REST service uses.   The column is going to store raw HTML that I am going to use in an ExtJs RowExpander plugin.   I create the new column and add it my ExtJs and nothing happens.  After figuring out it wasn't my code, I checked the REST service and the column was not there.

I verified everything and even restarted Notes.  To prove that the view was being read, I tried deleting a column and refreshing my browser page and sure enough the column disappeared.  To test the REST service I used the URL to see the raw JSON data.  (This is done by adding '/restData' after the Xpage URL, or whatever you entered for pathInfo).

You can see here that I am reading all columns
Here is where it gets weird.  If I enter any quotes string in the column value then nothing shows up.   If the string is the result of most any formula it works.   Note:  @Text("test123") did not work.  For clarity, the value "$91" is the programmatic name of the column "confirm91".

This doesn't work

Column value contains only text

This works

The column result is the same, but the column is now read.

Obviously the formula is fake, but for whatever reason the REST service now sees it.   Now that the REST service is pulling the column, I can use it in a grid of my choosing.  

Thursday, November 14, 2013

Creating a PDF dynamically from an XPage - Part 2

In my first post on the subject of creating PDF's dynamically from an Xpage, I went over the research that needs to be done prior to starting.   In this post I will first give an overflow of the workflow and then go into two specific problems I encountered while trying to get a working proof of concept.

Like I said in my last post, this process is fairly complicated.  I drew up this chart to show the workflow process.   To see a better workflow chart (not drawn in windows paint) see this one from Stephan Wissel.


Step 1:  User presses button, the code behind the button simply sets a sessionScope variable and the calls an xAgent Xpage.

Step 2:   The xAgent code first gets the XML from the backend data by calling a method of an utility class I wrote.  The method uses the generateXML() method of the 'Document' class.   The method will also gather XML from the line items documents as well, and merge them into a single XML document (I haven't wrote this part yet).

Step 3:  The xAgent calls a Java class which uses Apache FOB to transform XML into PDF.   It passes it the XML String and a URI to the location of the XSL stylesheet.

Step 4:  The transformation happens on the server and then presents the user with a dialog box to open or save the PDF.

Problem #1:   Can't get a Writer while an OutputStream is already in use Exception.  

This Exception is caused whenever you have any type of error in the SSJS of your xAgent.    In my case, I was modifying code written by Paul Calhoun.   I missed that there was an package statement that hadn't been changed.   I went ahead and put a Stack Overflow before figuring out what happened.   On my SO question, Tim Tripcony gave me an excellent answer on why that exception was happening and how to avoid it.   Even if you have no interest in creating PDF's you will be smarter for having read it.

Even after figuring this out, I did several things that caused the same exception.   In this context I would translate the exception to mean "Something is wrong with the code in your xAgent"  The best thing to do here it undo what you just did and figure out why the server is choking on your code.  Consider this a generic exception that can be caused by any number of issues.

Problem #2:  Getting a "WrappedRuntimeException" when trying to pass the XML to the Transformer

This problem really confused me until I turned to Stack Overflow and got a great answer from who else but Stephan Wissel.  Looking back, I should have seen this as it was obvious after the fact.  The Transformer class was expecting a URI String that points to the XML to transform.   I was passing it the actual String XML.   This was what caused the exception.  I had to modify the Transformer class slightly to convert the String XML to a StreamSource object that it was expecting.  (If I was using the same Transformer class for views, I would have changed it prior to passing it, I still should probably do this.)

Next Post

In the next post, I will explain how to created the XSL stylesheet, and my challenges with that.  I will also tell how XPath fits into all this.

Monday, November 11, 2013

Creating a PDF dynamically from an XPage - Part 1

In my Purchase Order project, one of the features I promised to the users would be a professional looking document instead of a printed web page.   Of course this was very well received by the users.  I felt comfortable suggesting this feature because I have previously watched videos showing that it could be done.

The demos that I had watched had one thing in common, they all showed how to create a PDF from a view. In my case, I need to create a single Purchase Order from the contents of an Xpage.  The Xpage that is the PO, actually shows header items stored in one document, and line items which are each stored in separate backend documents. There is an indeterminate number of line items associated with any given PO.   I quickly discovered that this piece of the project will not be easy, and in fact will be time consuming and difficult.  

In this post, the first of a series, I will document the steps to prepare to create PDF's from an Xpage.  The first step you will need to decide is which method to go about this.  The second step is to do your homework and understand the technique you decided to use.

Step 1: Deciding which technique to use.  

There are three distinct technologies available for creating PDF's.  The first is using an FDF file.  My friend Mark Roden was kind enough to give me an overview of this technique.   It seems like it is the easiest solution to create a PDF, but it does have some limitations.   You would use Acrobat (paid version) to create a form and then create a FDF file from your application to tell which data to be placed in which field on the acrobat form.   The format of the FDF is structured file that is neither XML or JSON, but seems pretty easy to pick up.

The limitation is that you would have to know that the number of fields that you need prior to creating the PDF.   In my case, a PO can have any number of line items, so I felt like using this technique would be too limiting.  If you can, I would recommend using this technique for how easy it is.  The techniques below are very different and more time consuming.

The second technique is to use iText.  I watched an older Notes in 9 video on using iText by Brian Moore. The video was very well done, and is a much watch if considering using iText.   I decided to forgo using iText because most of the more recent demonstrations that I found used Apache FOP instead of iText.  

This brings me to the third technique on creating PDFs, XSL-FO using Apache FOP.   My research led me to know that this was my best path to accomplishing my goal.  


Step 2:  Understanding how to use the XSL-FO and Apache FOP

The two resident experts in the Xpages world on using XSL-FO are Stephan Wissel and Paul Calhoun. Stephan has produced a series on his blog on how to use XSL-FO, it is must reading.    Paul has created an Notes in 9 that in 15 minutes or so shows you how to create a PDF from a view.   Paul also includes links to his demo on his site for all to use. 

The other useful site that I helped me was good ole w3schools.com.   They have whole sections dedicated to XSLT, XSL-FO and XPATH.  You will need to understand these 'languages' to create PDF's.   You will find yourself learning far more about XML than you ever cared to know.  Best to start brewing a fresh pot of coffee before diving in.

Next Post

In Part 2 of this series, I will document the pitfalls I encountered while trying to get a working proof of concept.  I also want to add that I am still plowing through all this, and I welcome in the comments any corrections if I say anything wrong. 

Thursday, October 3, 2013

When to use facesContext Redirect vs context Redirect + What I found in the bottom of my closet

I haven't had much useful to say lately.  I am just plugging along in my very large Purchase Order system project.   I think I have reached the point where I just want it done.  I know from experience that this means that I need to be extra careful to not cut corners and let my quality of work slip.  Today I did discover something worthy of sharing.

I discovered the difference between these two lines of code:

facesContext.getExternalContext().redirect("home.xsp");

context.redirectToPage("home.xsp");

On the surface they appear to do the same thing, but here is the difference.   The first one will continue evaluating the rest of the code before redirecting.  If that code happens to encounter a second redirect you will get an error that in Chrome looks like the following.


The second line will redirect the page immediately and you won't get the error.   I imagine that this has something to do with the JSF lifecycle if I had to guess.   If anyone wants to further elaborate then please comment.

Speaking of the JSF lifecycle, I think I am now ready to rewatch and this time understand the Xpages Masterclass.   I have watched at least the first two videos before, but honestly I wasn't ready for them.   I watched them back when they came out in the Spring and I really tried to understand, but mostly my eyes glazed over.  (Let me add my not understanding the material in no way reflects the quality of the presentation).  In my opinion, unless you are a genius this course won't help you much until you have gained some heavy real world xpages experience.  I will be diving into them soon.

Look what I found in my closet, who remembers these?

Lastly, I would like to join chorus in thanking Bruce Elgort.  I don't think I have ever met him personally but I have most definitely benefited from his efforts in the Notes community.   Thank you Bruce!

Thursday, September 12, 2013

Creating an Event for the Selected Row in an Xpages Data Table

Summary:

In this post, I wanted to show how I allow the user to select and act upon a whole row in a data table.   All the user has to do is single click on the row to make something happen.  I find that this works nicely for a desktop and especially nice for mobile users.

Attribution:

I discovered this method by following the advice of this post from Inner Ring Solutions.  I wouldn't have known that you can do this without their help.  This post will cover my own implementation of this technique.

Usage:

In my current project, it made a lot of sense to use a data table to display a list of line items.  I could have used a repeat, or a view control, but ultimately decided on the data table.   This works best when there is only one item to select, and you want to treat the whole row as a single unit.   After I created and styled my data table, I was surprised to discover that there were no events associated with individual rows.  The only events are associated with the table as a whole.  I thought I would have to switch to a view control, but then  I discovered the blog post from Inner Ring Solutions.
The user selects a single row, the mouse cursor (not shown) is on the second row.

How I did it:

The key to making this work using a property called "rowAttrs".   The name implies attributes applied to a row, but using this technique you can actually make an event  applied to a row.

This is the property that you use to apply to the whole row.
The really strange thing about using this property is that you cannot (at least I couldn't) use the script editor to enter a value.  When I tried to use this I would get compile time errors because it creates a different source. You can however use the source pane or enter text in the value.  It is important to give the 'attribute' a name of "onclick".  This how the server knows that this is an event.

Code must be entered in text in the value, you cannot use the Script Editor
In order to reference the selected row, you will need to enter a value in the "var" of the Data Table.  I enter the value of "line_items" as highlighted in the code sample.

The essence of what is happening here is that you can access backend data and pass it to a client side function.   In a alternative usage of this, in addition to passing a value from the current row, I also passed the value of a scoped variable.  

The last piece of this is the client side function.  I created this inside an output script control.  If you are new to xpages, this core control is not in the pallet by default, and can be found by choosing 'Create | Other'.  It holds clientside javascript you want to be loaded on this page.   I could have also used a clientside java library.

Opens the selected document

Alternate Uses:

This example uses the same method to delete a line item.   The function uses an AJAX call in jQuery to delete the document and then redirect the page in the call back.  (yes, I am quite proud of figuring this one out)
Deletes selected document
This example passes values to and calls an xAgent which in turn calls a java method, and then redirects the page using the value I pass in.   
Calling an xAgent and passing values to it

Conclusion:

I found this method very useful in cases, where you only want to select one row, and you want to minimize clicks or touches.   It has been very well received by the users I showed it to.   I haven't experimented with creating other events, but would think that "onclick" isn't the only one.  

Friday, August 23, 2013

view.postScript() only works for certain events on an Xpage

I discovered an undocumented feature today when trying to use the view.postScript() method.  This method (added in 8.5.3) allows you to run client side JavaScript at the conclusion of a block of server side JavaScript.  I discovered this issue, when I moved some code in the onClientLoad event of a Panel from clientside to serverside.   I needed to reference a value on the current document, and run a different function based on the value.

I thought to myself, "no problem, I will just use view.postScript() and it will run fine."   When I test the code, nothing happens.   The script never runs, and there are no errors.  I checked Firebug and the scripts loaded fine, as in I was able to launch them using the JavaScript console.  At that point, I did some googling and didn't find all that much out there on view.postScript().   I found a few articles, but nothing that helped me with my problem.

I then turned to Stack Overflow.  Sometimes, just the act of trying to write a question as clear as possible will cause me to think of the answer before I even post the question, but not this time though.  I went ahead and posted this question.

After I posted I got to thinking that maybe it wasn't my logic, but just that the code was being ignored.   I created a alert message using view.postScript and it still did not work.   I then tried putting that alert in the afterRenderResponse event of the xpage, where I had some other code.   Nothing happened there either. Frustrated, I then started putting the code in all the events, and to my surprise it worked some places and not others.  

Basically, the view.postScript() method only works in certain events.   I do not know why this is, but if I had to guess it has something to do with the JSF lifecycle.

I did some experimenting with the Xpage events and here is what I found.

  1. onClientLoad = nothing
  2. beforePageLoad = XSP error
  3. afterPageLoad = WORKS!
  4. afterRestoreView = nothing
  5. beforeRenderResponse = WORKS!
  6. afterRenderResponse = nothing
I can tell you that it doesn't work in the only Panel event, onClientLoad.  I am pretty sure I have used it with onClick events before, so it does work there.

The bottom line is when you view.postScript(), and you should, be aware that, if it does nothing then you might be using it in a place where it isn't supported.   In that case, first try a simple alert, and if that works then it is your code, if it doesn't then you can't use view.postScript in that event.   In my case, I moved the code to afterPageLoad and it worked great.

Monday, August 19, 2013

Managing Unwieldy URL's in Xpages

I wanted a way to control the URL's in the large Xpages application I am developing.  The application is customer facing after an authentication process.

My goals were to:

  1. Simplify the unsightly URL's 
  2. Prevent the URL's from revealing the presence of a second database
  3. Prevent the user from using bookmarks or the address bar and jumping into the middle step of a multistep process
I was able to accomplish the first two of these goals and this post will explain who I accomplished them.  The third goal is still outstanding.  I will make a follow up post when/if I figure that one out.

Before:   

This was the URL to open a document prior to making the changes outlined here:
http://notesdev1.my_company.com/po/po.nsf/%24%24OpenDominoDocument.xsp?databaseName=CN=My_Company_NotesDev1/O=MyDomain!!PO%5CPO-data.nsf&documentId=E879C68A9A88F6DD87257BC6005A0748&action=editDocument

This URL is very unsightly, and shows that I keep my data in a separate NSF.   It is also extremely long.   

After:

This URL does the same as the first and opens the same document in the same database
http://notesdev1.my_company.com/po/po.nsf/New_PO.xsp?doc=E879C68A9A88F6DD87257BC6005A0748

Notice that the URL does not reveal the location of the data, or my companies Notes domain.

The Remedy:

Before I explain here what I did, let me say that I would not have been able to come up with this without the help of Stephan Wissell and Per Henrik Lausten via Stack Overflow.   Here is the link to my question.   

The fix is two part.  

First, you have to manually build your URL in the container where you display your documents.   In my case, I am using a view control, which is really a placeholder until I decide how I want to display the data.   These instructions might have to modified for other containers.

A)  Give the View control a value in the 'var', I used 'viewData'
B)  In the onClick event of the column that is set to display as link, add the following code

var xpage = "New_PO.xsp"
var unid = viewData.getDocument().getUniversalID()
facesContext.getExternalContext().redirect(xpage + "?doc=" + unid);

The result of this is the after URL listed above.

The second part is to read the shortened URL:

In the Xpage Properties under Data, do the following:

A) Create your data source as you normally would
B) Specify the location of your data whether it is in the current NSF or another.  I prefer to separate data and design.
C) Change the 'Default action' to Open Document, or Edit Document
D) In the 'Document id' calculate the value to return param.get("doc") which grabs the UNID  that you passed

The result is that you have a nice looking URL and you can bind to any database without revealing it through the URL parameters.  I have read that you can accomplish similar results using site documents, but I wanted a solution that works whether your administrator is friendly or not. 


Thursday, August 8, 2013

Creating Tooltips in Bootstrap - Two Different Styles

In this post, I am going to go over the two different ways to make tooltips in Xpages using Twitter Bootstrap.

Background

I was wanting to create tooltips to shorten my labels and streamline a crowded window with many input fields in the application I am building.   After a quick search, I found an article that Kathy Brown wrote on how to create tooltips.   Within a few minutes I had a working tooltip, but I wanted tooltips that looked like what I saw on the Bootstrap site.
I wanted my tooltips to look like this
I tried a changing attributes using and couldn't do anything to change the default behavior.  I did remember to add 'data-' before the attributes.   After some searching and the help of jsfiddle, I was able to figure how the easiest way to create tooltips how I wanted them.

Option 1

This way is extremely simple and quick to implement.   In my case, I wanted to the tooltips to be on the labels.  You will notice that I am using a Bootstrap feature where I combine my input field with a label together using what is called an "input-prepend".   The label itself is wrapped in a <span> with a class of "add-on".   I wanted my tooltip to act on the label text in the add-on.   If you want the tooltip to act up on a control such as a button, you will want to add a new attribute (attrs) in All Properties of the control.

  1. Wrap your text in a span if it is not already OR Add a new attribute to control you are using.   In my case I am writing the html directly in the source.
  2. Add a property called "data-toggle" with a value of "tooltip"  See Update below
  3. Add a property called "title" with the text you want in the tooltip
Example:  <span class="add-on" data-toggle="tooltip" title="Seventh Street">02</span>

You will get a result like you see in the screenshot below.  The tooltip shows up in relation to the mouse location, always in the lower right.  You cannot control the location, or the delay.

The result of Option 1
UPDATE:  Upon further testing, I think a correction is in order.  Option 1 is not a bootstrap feature at all, but is part of HTML 5.   All you need is the "title" attribute to make this work.   The "data=toggle" does nothing.   

Option 2 is the Bootstrap way of writing tooltips.

Option 2

This is the way that tooltips are shown on the Bootstrap site, the first option isn't mentioned on the current site.  The first option would be fine and looks decent, but I wanted a little more control over placement and timing.

  1. Add a html property called "title" with the text of the tooltip.  (No need for 'data-toggle' with this option)
  2. If you already have a "class" attribute then add a second one separated by space.  Name it what you want, except don't use "tooltip" or it won't work.  I called mine "tips".  If you don't have a "class" attribute then create one.
  3. Add code similar to the following in your $(document).ready(function(). If you don't already have one that add one to the onClientLoad event of your Xpage, make sure you choose Client!
  4. Customize the tooltips however you want, using the bootstrap site as your guide.  In my case, I made the delay one second, and the placement always at the bottom.  With this option, the tooltip placement is based on the control it is attached to, and not the mouse location within the control.
Example:  <span class="add-on tips" title="West">01</span>
Code to enable the tooltip (Line 2 is unrelated the tooltip)

The result of Option 2

Wednesday, August 7, 2013

The Benefits of Using a Validator in XPages over using the rigid Validators

I know the Post Title might be a bit confusing, but so is the subject I am going to talk about.   The reason I am making this post is really for me, so that I don't forget how to do this.  I hope that it also might benefit others as well.   The reason that this is a confusing subject is that there is a "validator" property, and "validators" with the S that also do similar things.

Two months ago, I posted a question on Stack Overflow about trouble getting the xp:customValidator to work.   The answer that worked for me was by Paul Withers, thank you Paul if you ever read this. (My code below is a derivative of Paul's.)

Yesterday, I trying again to use one of the validators and getting frustrated with the result.  It was then that I remembered the better way of using "validator".  I have found that when I blog about something, then I own it, and am far less likely to forget how to do it.  In this post I am going to explain why I think using the validator is the best way to validate user input.

My issue started because I did not like the fact that my input fields would default to zero when bound to a managed java bean field of type double or int.   I decided that I would change the type in the bean to String, and then change my methods to use Double.parseDouble() to first convert the value to something that I can perform math on.   (If there was a better way to avoid the zero then I would like to know, please comment below)

To make this work, I first needed a xp:converter that converts the user input to String.

Without this converter you would get an exception when entering a numeric value.
I then needed to make sure that the user actually entered a number, and in my case that that number was not negative or a fraction.  This is the code I used in the validator property.

Validator code

Code Explanation

  • 'value' is something you get for free.  It is value the user entered.  I found this poorly documented.
  • The order matters, you will want to arrange the validators from general to more specific.
  • You have total control over the error message that you present to the user
  • Number() is a built in javascript function that converts a string to a number, it returns NaN if it cannot be converted.
  • The line that begins 'var msgObj' is long and includes the following line.
  • The line: this.setValid(false) prevents the submit.
  • I could combine these three statements into one message if I choose, but I prefer to give the user a message that tells them exactly what they are doing wrong.


So why use the Validator over the preset Validators

  • More Control:  You can make them fire in the order that makes sense to you.
  • You can show whatever error message you want.   The preset Validators sometimes decide for you.  In one case, it ignored the 'message' I put in, and still gave it's own.
  • You have unlimited flexibility in the conditions you want to validate.
  • The customValidator under the validators in unreliable and shouldn't be used IMO
NOTE:  For some reason you cannot recreate a validator that does the same thing as validateRequired.  You will have to use the global function.  They work together just fine.




UPDATE:

I didn't mention that with my examples, but I was also using a xp:validateRequired.  I didn't think to mention it.  I have discovered that when I remove that, the validator never fires when using Chrome.  It works fine on Firefox and IE, but not in Chrome.  If anyone has any clues why, then please comment or contact me directly at zavocki@hotmail.com.

The fix for this was to remove type="number".  It has something to do with the nice helper arrows that Chrome presents.  I would like to figure out how to use this attribute so mobile users see the right keyboard, perhaps some jQuery is in order.

Wednesday, July 24, 2013

Going with the ExtJS Grid, and giving up on Dojo Data Grid

I was really excited about using the features of the Dojo data grid, especially after watching Brad Balassaitis's TLCC webinar.   I think that Dojo grid has a lot to offer, but I have concluded that it just does not work for me.  I spent a lot of time trying to work through several issues.   The issues I had with it are: 
  • Issue with writing edited columns back to server
  • Spent way too long trying to figure out how to disable column sorting - was successful here.
  • Spend way too long trying to disable allowing user to adjust column widths - was unsuccessful here
  • Issue with blank lines when using viewItemFileService REST service, this was the showstopper
  • General inflexibility
  • Not much out there on the web for help, even Stack Overflow could not come through for me.
When researching a fix for my dojo grid problems, I came across a series of blog posts by Marky Roden from earlier this year (that I somehow missed) on the use of ExtJS within Xpages.  I have to admit that I had never heard of ExtJS, and upon first glance, I actually thought it was Marky's lingo for external javascript libraries.  Upon reading further, I came to realize that this is a real product, and a really awesome product!   

ExtJS is a lot more than just a grid, just as Dojo is a lot more than just a data grid.  It includes a multitude of various controls.   One key point about ExtJS is that it is not free, it is $329 if you just buy the license. Before starting out, I explained all my Dojo grid troubles with my manager, and he gave me the go ahead with ExtJS.  

With the ExtJS grid, you don't have a visual designer whatsoever.  It is not integrated with Domino designer like Dojo.  You have to copy the files to your WebContent folder and reference them in your xpage.  The coding itself is all done in client side javascript, it is all just code, with no code completion either.   It really helped to layout the basic code structure on my whiteboard.   I would definitely say that the learning curve is definitely greater, but so is the flexibility.  It was really nice in that I was able to find answers quickly in google for questions I had.   It was not so easy with the Dojo data grid.  The online documentation is really good, and doubles as a demo of all you can do with the product.

This afternoon, I was able to get the grid to appear and talk to my REST service.  The great thing was that I used the very same REST service that gave me the blank rows in the dojo grid, and with the ExtJS grid it worked how I expected with no blank rows.  I might be blogging more about ExtJS as I get more into it, but I will never match the helpful info here in Mark Roden's blog series.  In addition to posting how to use ExtJS, Mark has included a sample database where you dig into the code.  If you find yourself struggling like me with the Dojo grid, then this might be worth a look.

Monday, July 22, 2013

Creating an Updatable REST Service for use in a Dojo Data Grid

In my latest project, I am using a REST Service to pull data for use in a Dojo Data Grid.  I am using Brad Balassaitis's excellent blog series as a guide.   One issue that I came across was that I wanted to allow the users to edit values in columns and have them saved to the back end data.   

After much searching I found a link to XPages Extension Library book which says on page 178 that the xe:viewJsonService is read only, and that to perform edits or deletes, you must use the xe:viewItemFileService.  I already had the viewJsonService working, so before replacing it, I created a second REST service using viewItemService.  I copied all the columns and properties from one to the other, and the new one would give an "Internal Error 500".
This is the error you get when using the 'pathInfo' to view the service in your browser 
UPDATE:  It is not true that you must use the viewItemFileService.  You can use the viewJsonFileService to perform updates.   The error was caused because the PUT method was not allowed on the server.  In hindsight, I would not recommend using the viewItemFileService at all.

I did a lot of searching and could not find much on the subject until I came across this Stack Overflow where the asker was having the same issue as me.  Buried in the comments, Knut Herrmann answered the question.  On a related note, I really bugs me when Stack Overflow questioners abandon their question after they get their issue fixed.  This asker never responded to Knut if it worked, so that he could update his answer.

The fix, thanks to Knut, is that you use the 'keys' property instead of the 'categoryFilter', both are properties of the service.  I moved my code unedited from the categoryFilter to the keys and it worked with no errors.

It is OK that your view is categorized.   At first I thought this was the issue, because it began working after I removed the category.   The reason it worked was that the REST service ignored the Category Filter since there was not category.  I have since put the view category back and it still works perfectly.


To Sum up:

  • You must use viewItemFileService for backend Updates and Deletes
  • Don't use this:  <xe:this.categoryFilter><![CDATA[#{javascript:return myBean.getThisUNID();}]]></xe:this.categoryFilter>  Causes error 500
  • Use this: keys="#{javascript:return myBean.getThisUNID();  Works!

UPDATE:

This doesn't work as perfectly as I thought.   The REST service returns a different JSON format that causes blank rows in the data grid.   

These blank rows shouldn't be there
This is the REST service data
If anyone knows how to either modify the rest service or datagrid to suppress the blank rows, please comment!

March 2015 UPDATE:
Here is what I did to fix the issue with the blank rows.  I had to take a different approach. Please see this Stack Overflow question: http://stackoverflow.com/questions/29153238/how-to-configure-an-xeviewfileitemservice-on-an-xpage-to-filter-the-data-in-a-c/29182174#29182174

Friday, July 12, 2013

One case for not using a managed bean...

If you haven't figured it out yet, most of these blog posts are the result of a problem that I faced while working at my regular job, this post is no exception.  I needed to develop a case where a user could create any number of related documents that were related to the current document.

In my case each 'Line Item', could have an undetermined number of related 'Shipper' documents associated with that line item.   It was important that the Shipper documents were separate documents, and not part of a collection of the Line Item.   The reason being that I needed to emulate the back end data structure of the system I was replacing.

I knew how to create this functionality using Serverside Javascript, as I had done in my last project, but for this project I am using managed java beans and trying to keep my business logic in java and not all over the place.   I look back at my first big xpages project, and sometimes I cringe at how I designed certain parts of it.  It is not that I am not proud of it, it is just that I know so much more now than I did just 4-5 months ago.   

Back to my issue, what I was attempted to do was to create a Shipper managed bean.   I then bound the four input fields directly to the bean, and then called the saveShipper() method of the bean.  This did work, but only for the first  Shipper doc.  If I tried to create another document, nothing would happen.   After trying many things, I came to the conclusion that fundamentally  I was doing something wrong.   At this point, I decided to call on Stack Overflow, and see what advice I could receive.    Here is a link to my question.  (I think I could have chosen a better title but so be it.)

The advice I received was good from all three who answered, but the advice that helped the most was from Peter Presnell when he said "I would suggest not using a managed bean as it does not seem to add much value to your process. "  He went on to say that the way I was attempting to reuse the managed instance causes issues.   I now have firsthand knowledge that this approach causes issues.   This got me to thinking that there were cases where using a managed bean was not the best way for coding.

For cases when you have more than one related objects that you want to create, and each should be saved independently, the best approach (IMO) is to make the object a POJO or Plain Old Java Object. 

One thing to understand about managed beans is that there is always only one instance of each.  I don't think I quite understood this before I came across this problem.


The only changes I had to do to convert the bean to a POJO was to:

  1. Remove the reference in the faces-config file
  2. Create a constructor with arguments accepting values for each instance variable
  3. Change the binding of the input fields from the bean to a RequestScope variable
  4. Change the button to create the new object in SSJS.  See example below.
The code to create the java object in SSJS is:
var x - new com.yourpackage.pojoName(requestScope.field1 ...);

You can then call any method of the object by using the reference you used which was 'x' in my example.
x.savePojoName();

In my case, I create a new object each time, overwriting the previous one.   

I am glad this issue happened, as now my mind is more open to ways to use regular java objects in my applications.

Friday, June 28, 2013

Issue with Referencing an Xpages generated #Id using Bootstrap

UPDATED

I am not sure if this is a Bootstrap issue or an HTML5 issue, but there is an issue when referencing the long generated ID files in Xpages.   ID's like 'view:_id1:_id2:_id41:_id43:include1:shipper'

Today I was working on a form where the user can press a checkbox, and it will reveal additional entry fields.   I am using the features of Bootstrap to accomplish this.  It looks great and works like this:

When first loaded
With the checkbox checked
Using bootstrap, this is amazingly easy to accomplish.   The part that you want to initially hide is wrapped in a <div>  with a class="collapse in".  The collapse tells Bootstrap that this is the div you want to expand and collapse, and the "in" means that you want to start collapsed.

In the checkbox, you simply set two attributes:  data-toggle="collapse" and data-target="#the id of the div">.   That is all you have to do to make it work, really.

All went well until I changed from using a <div> to an <xp:div>.  I wanted more control over the attributes, specifically it was defaulting to "in" but I wanted to compute whether to start "out" or "in" based on whether the checkbox is already checked for existing documents.

When I started using the XSP div, I could not get it to open and close based on the checkbox.  It took me a long time of playing with the attributes using Inspect Element in Chrome to determine that Bootstrap does not like colons in ID's.

The fix is to escape your colons with a double backslash (\\) in SSJS.  When it gets to HTML, the value will be a single backslash which will escape the colon and in your id when referencing it.

This is NOT a good way of fixing this.  For a better way, see below.

I found out after I posted this that if the ID were to ever change then your code will break.   A big thanks to David Leedy who let me know that my code has potential issues.  He also pointed out to me that Marky Roden has made an excellent xsnipet for handling the unreadable colons.  

The Better Fix
  1. Copy Mark Roden's xsnipet into my clientside javascript library.
  2. Removed the attribute 'data-target' from your <xp:div>.
  3. In my $(document).ready() function, I added the following line of jQuery  $('input.checkbox').attr('data-target', x$("#{id:shipper}").selector);
UPDATE #2: I found out that if you do a partial refresh on the page, you will lose the fix if you leave it in the document.ready() as shown above.   The fix is to move the jQuery the clientside event of you partial update.

The jQuery was easy to write.  It simply adds an attribute to the checkbox calling the x$ function which selects the <xp:div> with a name of 'shipper'.   The '.selector' property returns the ID name.  This works just the same as before but is a much better way of coding this.  (Note: that I will only have one checkbox on this page, otherwise I would have to be more specific with my jQuery selector.)


I hope this saves someone some frustration when using ID's in Bootstrap.

Thursday, June 27, 2013

Dynamic Computed Values in an XPage without Javascript

Yesterday, I was trying to created a Computed Field on an Xpage that is based on the editable values of input fields on the same page.   My application is using managed beans to persist all backend data prior to writing it out to a NotesDocument.   Admittedly, I was a bit tired, but all I could think of how to do this was to use Serverside Javascript or Clientside Javascript.  I am comfortable with either method, but I had this nagging doubt that there must be a better way since I was already using java.

I decided to put in a Stack Overflow and ask what was the best practice for computed values using beans.   Stephan Wissel answered my question and the answer was fairly simple.   I was thinking along the correct lines that there was a better way than javascript.   Stephan said that I need to remove my set method from the bean, and to put my logic in the get method.

Sure enough, this worked just as he said.   I was somehow under the impression that each instance variable of the bean had to have one getter and one setter, like it was a required part of the bean specification.  It turns out that this isn't exactly correct, I commented out the set() method and it automatically turns the bound input to read only.  I never had learned this before so I thought it worthy of sharing.   Of course the nice side benefit of blogging this, is that I am now 10x more likely to remember this.

The logic for a computed field goes in the Get() method.  For some reason I was thinking the opposite.  To make the value dynamic, I put the computed value in a different container than the editable fields, and did a partial refresh of the container in the onChange event of each input field used in the calculation.  I really like the result.   All of this amounted to an additional six lines of java code in a method that I already had.

To create a dynamic field in summary:

  1. Bind directly to the bean using expression language.  If you are using beans, then you are likely already doing this.  I used an 'Edit Box' to store my 'computed field'.
  2. Comment out or remove the set----() method in the bean
  3. Put your business logic in the get----() method of the bean
  4. Put your dynamic field(s) in a different container element
  5. Refresh the container element using partial refresh

Friday, June 21, 2013

Simple Fix in Eclipse for when your Managed Bean Cannot Be Instantiated

Today, I added a second managed bean to my application.   I wrote the Java code and added the bean name, class, and persistence to my faces-config.xml file.

No matter what I did, as soon as tried to reference the bean, I would get an ClassNotFoundException.   Basically the application was not seeing the reference in the faces-config file.   I spent most of my energy thinking I somehow had improper syntax in the file.

A quick search found this Stack Overflow, and the comment by Mark Leusink did the trick.   I did a Project  | Clean in Eclipse, and the managed bean worked as expected.   The Project | Clean will launch a window where you can choose any or all of the projects in your 'Application' window.

Hopefully this will be helpful to someone.  I know I am going to try it whenever strange things are happening in my xpages projects.  BTW:  I am using Notes 9.

Tuesday, June 11, 2013

My First Experience with Managed Java Beans in an Xpages Application

In my latest application, I decided early on that I was going to use Managed Beans for my business logic.   Prior to starting I read and listened to everything I could find about them.   I am not going to explain how they work in this post, except to point you in the direction of the resources I used.

I learned about JavaBeans way back when I first started studying Java.   I learned Java by taking three credit classes at Northlake College in Irving, TX.  My instructor worked at IBM and was an excellent teacher.  JavaBeans were basically one chapter towards the end of my studies.  I think Java Server Faces, of which xpages is an implementation of, had just come out.   JSF was only touched on in lecture but was too new for the textbook.

Fast forward to today, I am pretty sure it was a Notes in 9 episode when I first heard about them.   I had already created two xpages applications without using them, so I really wanted to know what is in it for me.

The best resources today that I would recommend to learn to use managed beans is to watch Russ Maher's 2 hour Jumpstart from Connect 2013.   IBM has posted the video here (Thank You IBM!!).   It covers the same material he used in his Notes In 9 episodes in even greater detail.   Another great resource is this youtube presentation on Java for Domino Developers by Paul Calhoun.  It also runs two hours.

My use of Managed Bean is fairly simple at this point.   I use them to hold the data they enter as they click through a data entry wizard.   The data is only stored in the bean until they get to the final step.   I then write the data as a new document.   If the users quits in the middle, then I wipe clean the contents of the bean.  The bean also allows users to go forwards and backwards through the screens and see the data they entered.  Later, if the user edits the existing document, the bean is reloaded and then updates the backend document upon completion.   It can be done but it would be a pain to do all this without using managed beans.

Here is my code.   Like I said, this is pretty simple, but I think would be good to someone just getting started. I make a few comments in red.   I also cut out most of the instance variables to make this shorter.   The scope my bean is using is "session'.

import javax.faces.context.FacesContext; 
import lotus.domino.Database;
import lotus.domino.Document;
import java.io.Serializable;
@SuppressWarnings({"serial"}) 
 **I saw someone else do this to suppress warnings so I copied it,think it must be part of Eclipse**

public class StatusBean implements Serializable {
private String status;
private String typePO;
private String unid;

**These getter's and setters were generated by Eclipse. They are required**

public String getTypePO() {
return typePO;
}
public void setTypePO(String typePO) {
this.typePO = typePO;
}
public String getStatus() {
return status;
}
public void setStatus(String status) {
this.status = status;
}
public void setUnid(String unid) {
this.unid = unid;
}
public String getUnid() {
return unid;
}

public StatusBean(){
                //zero argument constructor 
**You can have other constructors if you want but you must have one like this.**
}

 **This method wipes the contents of the bean, used when cancelling***
public void deleteAllHeaders(){
this.typePO = null;
this.status = null;
this.unid = null;
}

***This method saves the new document and returns the document unique id to the caller***
public String saveNewDocument(){
String unid = "";
try{
*One very long statement below*
Database database = (Database)FacesContext.getCurrentInstance().getApplication()
.getVariableResolver().resolveVariable(FacesContext.getCurrentInstance(), "database");
Document doc = database.createDocument();
doc.replaceItemValue("form", "PO");
doc.replaceItemValue("status", status);
doc.replaceItemValue("typePO", typePO);
doc.save();
unid = doc.getUniversalID().toString();
}
catch(Exception e){
e.printStackTrace();
}
return unid;  //return new UNID to the calling SSJS function
}
}

Even if you don't know Java, I wouldn't call this hard stuff.   It really doesn't read much different than server-side JavaScript.   I haven't written the methods to edit and update existing documents yet, but I don't see that being very complicated.   I have to say I really love this way of coding.