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!


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:

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.

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.