Saturday, January 31, 2009

Sorting a rich:subTable

My next problem to solve is how to sort a rich:subTable. I need this because I am displaying detail rows using rich:subTable and when user clicks on the header for the main table the data should be sorted by the column clicked in subTables also.

Then what is the problem, richfaces documentation shows we can use sortPriority and sortBy properties on subTable, unfortunately after 3 days of relentless attempts I found out from the richfaces source code that subtable is not a sortable component , so you cannot use the goodies like automatic sorting complete with nice ascending and descending marking icons.

I must implement subTable sorting because without it I cant go ahead with richfaces for my project as i need master and detail sorting in almost all the screens, so I decided to come up with some solution.

One solution is to sort all the detail rows when ever user clicks on table header, like this algorithm

for each row in main table
if there are group elements for this row sort them


This works very well and it worked too,but some how i did not liked the way it is sorting all the detail rows everytime I clicked on header, as at any point of time i display only 15 rows per page. It makes sense to sort only the details of 15 rows, after some thought here is my solution

1. Building upon my previous post where I used SortingBean to help in external sorting, add a method to SortingBean which takes a list and sorts that list based on the column provided and the sorting order
2. change the subtable definition

From:





...




To:

 



...




This approach works very well because pagination will ensure that only the rendered rows are sorted as opposed to sorting all detail rows

Sunday, January 18, 2009

External Sorting in seam application with rich:dataTable

When working with seam application you may have encountered a scenario where you have to implement rich:dataTable in a non-conventional way , for example look at the below fragment


NORMAL WAY





Symbol

#{aRow.symbol}




Quantity

#{aRow.quantity}


...
..
A MORE FLEXIBLE WAY..






Symbol
Quantity



#{aRow.symbol}



#{aRow.quantity}




notice the second case, that we are not defining the table headers with "header" facet for each column, instead we are defining all the header columns using a single header facet. This allows me to do stuff like detail rows for each row using subtable and columngroups easily. This approach brings a problem too, it is not easy to define sorting information to take advantage of automatic sorting feature of dataTable. Rich faces demo gives an nice example of using external sorting, but it may not be very obvious on how to implement sorting by clicking on header rows, atleast for me it was little difficult to get around this problem. Actually it is not that difficult , here is how hey do it....

1. We need to make use of dataTable's sortPriority property to tell dataTable which column the table should be sorted on.
2. Define IDs for all the columns you want to provide sorting ability
3. Make the header clickable and on click event change the sort priority (dont worry if this is not clear, I will explain you in detail.. shortly)


Because we need to use the same feature for many screens , we will not write anything in our conversation scoped sessionbeans , instead we will define a reusable bean which can store the sortPriority and sortOrder , as per rich faces documentation I named the bean SortingBean, less surprising. huh..

it is a simple bean which holds the current sort column and sortingOrder (ASCENDING or DESCENDING), here is the class

package com.dezinx.shareguru.utils;

import java.io.Serializable;
import java.util.ArrayList;
import java.util.List;

public class SortingBean implements Serializable {

/**
*
*/
private static final long serialVersionUID = 3478316227248532205L;

private String sortingOrder;
private List sortingPriority;

public SortingBean() {
sortingOrder = "ASCENDING";
sortingPriority = new ArrayList();
}

public void sortOn(String columnName) {
if (sortingPriority.contains(columnName)) {
toggleSortingOrder();
} else {
sortingPriority.clear();
sortingPriority.add(columnName);
sortingOrder = "ASCENDING";
}
}

private void toggleSortingOrder() {
if (sortingOrder.equals("ASCENDING"))
sortingOrder = "DESCENDING";
else
sortingOrder = "ASCENDING";
}

public String getSortingOrder() {
return sortingOrder;
}

public void setSortingOrder(String sortingOrder) {
this.sortingOrder = sortingOrder;
}

public List getSortingPriority() {
return sortingPriority;
}

public void setSortingPriority(List sortingPriority) {
this.sortingPriority = sortingPriority;
}
}


Now we have to expose this sortingBean to the view and it can be easily done by outjecting the instance of SortingBean , like below, in your seam action (stateful session bean)


.....
@Out(scope=ScopeType.CONVERSATION)
SortingBean sortingBean;
...




Finally , lets define the view


..





Price



Quantity




#{aRow.price}



#{aRow.quantity}





in the above code, take notice of how we set selfSorted property to false , defined column ids to refer in a:support , which fires an ajax request to set the current column to sort, Also notice that a:support has reRender attribute set to the id of dataTable, which will force a table rerender after click on table header.

Hope this helps.

Monday, November 17, 2008

Changing Effects without resorting to javascript in RichFaces JSF

Recently I had to use <rich:effect> to make a richPanel appear with BlindDown effect on user action. It was easy for me as I just had to use code as below to accomplish this

 
.....





Just as it was given in RichFaces Demo site. Now I had to do this tricky part, I have to show the panel when user clicks the link "click" for the first time and BlindUp to close the panel when clicked again. I know we can easily do it with javascript as it just uses the scriptaculous library, I wanted to avoid javascript (rather explicitly in JSF applications), so came up with this solution.

As I will be toggling the effect for panel based on the values that I am going to display from my seam action, i wanted to use the data to differentiate if I need to show or hide the panel

 
.....








Note that the oncomplete handler is unchanged (where I thought I will have to call a different javascript here initially ..), we will be changing the effect type based on our business specific condition which can help us determine whether to close the panel or to open it.

Also notice, that the style element for the richPanel is set to display:none or display:block , this is to hide the panel initially so that BlindDown effect make sense.. and similarly used display:block to make sure user can see the effect of panel hiding using the BlindUp effect


..

..


Thursday, November 6, 2008

Readonly Value Binding in JSF for a hidden field

Many of the newbies of JSF will encounter situations where they find everything they wrote perfect but the JSF implementation throws strange errors. Here is one of the classic ones that you may step on.. .

Imagine you want to store some number(like some count) in a hidden field so that you can use it in your javascript to perform some task.


     .....
     
     
     


you strongly know this should work fine, particularly when you are coming from a JSP/struts/struts2 background, but when this page gets submitted you will see errors from JSF saying that the count is not writable for int . This is because there is no setCount method on the someList bean, Although we are not writing anything to the hiddenField, we have to understand when ever a form gets submitted JSF tries to apply back the values into the component tree.

How to solve this ? Here is how they do it.

just add readonly="true" attribute to h:inputHidden, this will ensure JSF will not try to apply values through setCount method, but still renders the value to the page


     .....
     
       
     
 


Hope this helps..

By the way ..this is my first post from my new MacBook Pro :-)

Friday, March 21, 2008

Quick Sequence diagrams

Though there are great tools available to draw UML diagrams , some times we will be in a situation to quickly draw a sequence diagram for a presentation or to discuss some thing in a design meeting and we dont want to waste our time working with those heavy tools.

I came across http://www.websequencediagrams.com/ and felt this a cool site in which we can describe our sequence diagrams using simple text like A->B:create() to produce cool diagrams like the below image.

how to access constants from JSTL (EL)

During our web development we may come across a situation where we want to use a constant (static final) variable for some reason in our JSP using JSTL's Expression Language (EL). As you know we access properties very easily using JSTL as below.

you might alreay know.. if we want to access a property called studentName and a method is defined as getStudentName() in the target object (lets cal it 'student') the EL would be "${student.studentName}".

But if we want to access a constant defined in the above class as
public static int MAX_RETRY_ATTEMPTS=10;

using the EL "${student.MAX_RETRY_ATTEMPTS}" , will fail
I am sure you will need to use these constants sometimes.

We can use a simple trick to solve this.

we will make use of a Map to store the constants , as below


.....
.....
......
public final static int MAX_ALLOWED_USERS=10;
public final static int MAX_LOGIN_ATTEMPTS=2;
Map constants=new HashMap();

public Map getConstants(){
constants.put("MAX_ALLOWED_USERS", MAX_ALLOWED_USERS);
constants.put("MAX_LOGIN_ATTEMPTS", MAX_LOGIN_ATTEMPTS);
return constants;
}


As you can see we have defined a method getConstants which returns a HashMap with our constants with appropriate keys.

Now how can we use this in our JSP ?


The Maximum number of attempts is : "${MyForm.constants['MAX_LOGIN_ATTEMPTS']}"


clearly, we first get the Map using getConstants() method and then value of the constant using the key 'MAX_LOGIN_ATTEMPTS'.

Easy ?

Please let me know if there is a better way to do this

Wednesday, March 19, 2008

What's nice about seaside ?

Its been very interesting week, trying to get my head around seaside. Honestly it took some time for me to unlearn many things which I learned over past many years. Not only a great idea, I feel it will speed up the the web development process in a great way. Although many seaside experts have written great examples, I wanted to post the one I started with.

The functionality is quite simple
1) Display the Login Page
2) User enters username and password and clicks on validate button
3) If the credentials are validated (in this case username='smalltalk' ) a welcome message is displayed , otherwise login page is displayed again.

Quite simple.... lets see how intuitive it can be

Lets start with defining our Login Component as below



WAComponent subclass: #Login

instanceVariableNames: 'username password retry'
classVariableNames: ''
poolDictionaries: ''
category: 'LearnSeaside'!



this should be self explaining , We defined a class Login subclassing it from WAComponent.
It has three instance variables , I used "retry" to indicate if it is a retry or first attempt. (may not be the best way ..)

Seaside calls renderComponentOn method when it is appropriate to display the content on the web page. Let us look at how we want to display the content on page.


renderContentOn: html

html
form: [
retry ifTrue: [
html text: 'Retry..'.

html break].
html text: 'User Name'.
html textInput on: #username of: self.
html passwordInput on: #password of: self.

html submitButton callback: [self answer: self];
value: 'Validate']



Nothing special .. it just displays user name and password fields, in addition to that , it display text "Retry" based on the instance variable "retry".

Now lets add some magic. we will now write a Task to start this.

we will name our task WASchoolTask , subclassing WATask. it will have a method "go" which will be called by seaside as entry point to the application.

let us look at the go method.


go
| login |
login := self call: Login new.
[login username = 'smalltalk']
whileFalse: [login retry: true.
login := self call: login].
self inform: 'Welcome ' , login username

as you can see in the above code we want to display the login screen until the user enters username as smalltalk. What a great way to write your applications describing the natural flow of the application! Notice the statement
self inform:'Welcome ',login username

The best part of the code is that this statement will not be executed unless the loop is broken. Imagine how you would do this in a Action based framework.