Tuesday, October 13, 2009

How Can I bind the jsf properties dynamically?

In my previous post I explained how you would be able to create the controls dynamically, now it's time to bring this baby alive!

First, let me explain how you would create Value Expressions (that will be used by faces to get the values) and bind them to your recently created HtmlInputText,


FacesContext facesInstance = FacesContext.getCurrentInstance();
Application application = facesInstance.getApplication();
ExpressionFactory expressionFactory = application.getExpressionFactory();

String expression = "#{myMode.myProperty}";
ValueExpression valExpression = expressionFactory.createValueExpression(facesInstance.getELContext(), expression, String.class);

HtmlInputText text = new HtmlInputText();
input.setValueExpression("value", valExpression);


Easy, isn't it? the first 3 lines will get the context required to create the ValueExpression, the line "String expression = ..." just creates the string expression, the one that you usually put in the value of the h:inputText in your jsf page. The next two lines create the expression and assign it to the "value" property of the html input text. You could use this in the required or rendered fields (any property that you could use as EL in your page).

This solution works well if you have your properties hardcoded in your bean, but how will this work with a really dynamic solution? (if you already know them, why will you need to create all the dynamic controls in the first place?)

Ok, here the Expression Language will do the trick, the Expression Language allow you to put Maps as properties in your code, so you could create your own Map to your dynamic properties and that's it! here's a sample of the Map (I will not put all the methods you should figure out how to solve the others, but it's very simple)


public class MyPropertyMap implements java.util.Map {
private java.util.HashMap internalMap;
public EntityMap() {
internalMap = new java.util.Map();
internalMap.put("PropertyA", 1);
internalMap.put("PropertyB", "A text property");
internalMap.put("PropertyC", True);
}

public Object get(Object key) {
return internalMap.get(key);
}

public void put(Object key, Object value) {
internalMap.put(key, value);
}

... (all the other methods required by the Map interface)
}

public MyModel {
private MyPropertyMap map = new MyPropertyMap();

public Object getMyPropertyMap() {
return map;
}

public void setMyPropertyMap(MyPropertyMap map) {
this.map = map;
}
}


finally your dynamic control creation should look like this:


FacesContext facesInstance = FacesContext.getCurrentInstance();
Application application = facesInstance.getApplication();
ExpressionFactory expressionFactory = application.getExpressionFactory();

String expression = "#{myMode.myPropertyMap['PropertyA']}";
ValueExpression valExpression = expressionFactory.createValueExpression(facesInstance.getELContext(), expression, Integer.class);

HtmlInputText text = new HtmlInputText();
input.setValueExpression("value", valExpression);
myPanel.getChildren().add(input);

String expression2 = "#{myMode.myPropertyMap['PropertyB']}";
ValueExpression valExpression2 = expressionFactory.createValueExpression(facesInstance.getELContext(), expression2, String.class);

HtmlInputText text2 = new HtmlInputText();
input2.setValueExpression("value", valExpression2);
myPanel.getChildren().add(input2);

String expression3 = "#{myMode.myPropertyMap['PropertyC']}";
ValueExpression valExpression3 = expressionFactory.createValueExpression(facesInstance.getELContext(), expression3, Boolean.class);

HtmlSelectBooleanCheckbox chk = new HtmlSelectBooleanCheckbox();
chk.setValueExpression("value", valExpression3);
myPanel.getChildren().add(chk);


and that's it... you have a full Dynamic page! (I hope you noticed how the 3rd parameter of the createValueExpression changed for each control, Integer, String and Boolean).

Ok, with this you will have a full dynamic solution, the next part will show you how you could create dynamic navigation using dynamic parameters.

No comments: