Tuesday, October 13, 2009

Dynamic JSF

Recently I came across with a "problem", how can I create some JSF pages more dynamic than usual?, for example adding new controls on the fly using metadata from somewhere else. I decided to write this article because it's a little hard to find information about this subject, and when you find it you could not spot all the solution and all the problems that will face in the real life :D.

This is not a solution I invented and I can barely remember all the links I read in order to understand the whole picture, later I will try to look at my browser history in order to compile them and give the credit they deserved.

Ok, here is the description of the problem I want to solve:

How can I create dynamic controls for a page that needs to be solved on runtime? the application I'm working on is a BPM engine (BizAgi) that constructs its pages based on metadata information stored in a DB, so it's not possible to write the controls from the beginning.

The solution is fairly simple and has 3 parts:

1. Dynamic creation of the controls
2. Dynamic mapping of the properties
3. Dynamic redirection to a JSP using parameters.

Dynamic control creation

This is the easy part and there's a lot of documentation in internet about this subject, and the steps are easy:

1. Create a Panel in your JSF page
2. Bind the panel to a property in your backing bean
3. Add the controls in your backing bean

so, here's how it's done:

create a bean class (model class) with a property of type javax.faces.component.UIPanel like this:


public class MyModel {
private javax.faces.component.UIPanel myPanel;

public javax.faces.component.UIPanel getMyPanel() {
return myPanel;
}

public void setMyPanel(javax.faces.component.UIPanel myPanel) {
this.myPanel = myPanel;
}
}


Next just bind it in your jsf page like this:


<f:view>
<h:panelGrid binding="#{myModel.myPanel}" />
</f:view>


we're close to finish, the next step is where the fun begins, just add the code to create dynamically the controls, like this:



public void setMyPanel(javax.faces.component.UIPanel myPanel) {
this.myPanel = myPanel;
if (myPanel.getChildCount() <= 1) {
HtmlInputText input = new HtmlInputText();
input.setValue("my dynamic text");
myPanel.getChildren().add(input);
}
}


At this point, I'm sure you noticed the "getChildCount() <= 1"... why is that? just because everytime the postback is called the faces framework will set the panel with the last controls added to it, if you don't control that you will get a panel with multiple text everytime you hit the "save" button. I know, you can do this in several ways, but this is an example!

Ok, this is the point where all the "blog" gurus stop and you get yourself in the middle of nowhere!, you must ask questions like... how will I bind that to dynamic properties instead of static texts? or, how would I manage the state... etc.

Because the blog is getting longer than I thought I will split this in some parts...

How can I bind the jsf properties dynamically?
How can I send dynamic parameters to other JSPs? or JSFs?

As usual please forgive my pour english, I'm hoping to improve it with every post xD

No comments: