wissel.net

Usability - Productivity - Business - The web - Singapore & Twins

Binding controls to managed beans


Out of the box XPages connect to Notes Views and Notes Documents as data sources. Other data souces require some advanced skills you might not be ready to invest. However controls can be bound to many things, data sources are just one of them. Under the hood the data binding uses the JSF Expression Language (EL). Since XPages knows a JavaScript binding you can bind your control to any JavaScript function, but that's not what I want to show today. One very interesting option (that is 1:1 JSF) is to bind your controls to a managed bean. So what is a managed bean? It sounds more complicated than it is. The bean part is a standard Java class that has a constructor without parameter (which is the default for a Java class anyway) and get/set methods pairs (more about that in just a moment). The managed part is an entry in the faces-config.xml where you define a "friendly" name for a Java class as well as the scope. If you use that friendly name in code (in SSJS or EL) the class instance is automatically created for the defined scope if it doesn't exist yet in that scope. Once the scope expires the object is automatically discarded. Since this works automagically the Java class is called "managed". An entry in your faces-config.xml (to find that file, open the Navigator view and look for /WebContent/WEB-INF/ in your NSF) could look like this:
  <managed-bean>
    <managed-bean-name>demo </managed-bean-name>
    <managed-bean-class>com.demo.ELTest </managed-bean-class>
    <managed-bean-scope>session </managed-bean-scope>
  </managed-bean>
With this entry a new top level object demo is available for use in EL or SSJS in the same way as you can use database, session, context etc. Our class is valid for the session context, so multiple XPages will see the same content. You can name your methods inside the Java class as you like and call them in SSJS, e.g. demo.playTune(). The more interesting use however is the bean use. If your (real live) object has e.g. 3 properties: Name, Color, Taste, then you would have 6 methods in Java, 2 each for each property: getName(), setName(newName), getColor(), setColor(newColor), getTaste(), setTaste(newTaste).
Once you follow this pattern you can refer to that property in EL just by its name: demo.name, demo.color, demo.taste (Note: no brackets here!). You enter that in XPages data binding in "Advanced / Expression Language". It will however appear in the regular data binding setting with the bean's friendly name as name of a data source.
A little stumbling block: the properties start always lowercase, while the first letter after get/set must be uppercase. Also the get function needs to return the same data type as the set function takes in as a parameter.
XPages inspects the bean for the get/set functions. If the set function is missing a control is automatically rendered read only, while a missing set function leaves an entry field empty. Once data is posted back to the server the set functions of your bean are called and it is up to you what to do with the data. Having named get/set function is great when you exactly know your object at design time. A very typical use for a bean binding however is retrieving a data set where you don't know what is coming. EL also can cater for that. Your Java class needs to implement a property that returns a Java MAP in a pair. e.g. Map<String, String> getStuffProperties(); void setStuffProperties(Map<String, String> newProps); Once you have that you can write as data binding in EL: demo.stuffProperties["Color"]. Here you have the freedom to use upper- or lowercase property names as you like. Of course you are not limited to a static string and have any expression EL is capable of at your disposal. This makes a quite powerful construct. Try it yourself! Use this simple Java class:
package com.demo ;

import java.util.HashMap ;
import java.util.Map ;

public class ELTest {

    private String color ;
    private String taste ;
    private String name ;
   
    private Map < String, String > fruitProperties = new HashMap < String, String > ( ) ;

    public String getColor ( ) {
        return color ;
    }

    public void setColor ( String color ) {
        this. color = color ;
        this. fruitProperties. put ( "Color", color ) ;
    }

    public String getTaste ( ) {
        return taste ;
    }

    public void setTaste ( String taste ) {
        this. taste = taste ;
        this. fruitProperties. put ( "Taste", taste ) ;
    }

    public String getName ( ) {
        return name ;
    }

    public void setName ( String name ) {
        this. name = name ;
        this. fruitProperties. put ( "Name", name ) ;
    }

    public Map < String, String > getFruitProperties ( ) {
        return this. fruitProperties ;
    }

    public void setFruitProperties ( Map < String, String > fruitProperties ) {
        this. fruitProperties = fruitProperties ;
    }
       
}
 

together with these two pages:
<?xml version="1.0" encoding="UTF-8"?>
<xp:view xmlns:xp="http://www.ibm.com/xsp/core">

    <xp:table>
        <xp:tr>
            <xp:td>
                <xp:label value="Name" id="lblname" for="txtName"></xp:label></xp:td>
            <xp:td>
                <xp:inputText id="txtName" value="#{demo.name}"></xp:inputText></xp:td>
        </xp:tr>
        <xp:tr>
            <xp:td>
                <xp:label value="Color" id="lblColor" for="txtColor"></xp:label></xp:td>
            <xp:td>
                <xp:inputText id="txtColor" value="#{demo.color}"></xp:inputText></xp:td>
        </xp:tr>
        <xp:tr>
            <xp:td>
                <xp:label value="Taste" id="lblTaste" for="txtTaste"></xp:label></xp:td>
            <xp:td>
                <xp:inputText id="txtTaste" value="#{demo.taste}"></xp:inputText></xp:td>
        </xp:tr>
        <xp:tr>
            <xp:td></xp:td>
            <xp:td>
                <xp:button value="Update" id="button1"><xp:eventHandler event="onclick" submit="true" refreshMode="complete" immediate="false" save="true"></xp:eventHandler></xp:button></xp:td>
        </xp:tr>
    </xp:table></xp:view>
 
and here the Map bound version:
<?xml version="1.0" encoding="UTF-8"?>
<xp:view xmlns:xp="http://www.ibm.com/xsp/core">

    <xp:table>
        <xp:tr>
            <xp:td>
                <xp:label value="Name" id="lblname" for="txtName"></xp:label></xp:td>
            <xp:td>
                <xp:inputText id="txtName"><xp:this.value> <![CDATA[#{demo.fruitProperties["Name"]}> </xp:this.value></xp:inputText></xp:td>
        </xp:tr>
        <xp:tr>
            <xp:td>
                <xp:label value="Color" id="lblColor" for="txtColor"></xp:label></xp:td>
            <xp:td>
                <xp:inputText id="txtColor"><xp:this.value> <!DATA[#{demo.fruitProperties["Color"]]> </xp:this.value></xp:inputText></xp:td>
        </xp:tr>
        <xp:tr>
            <xp:td>
                <xp:label value="Taste" id="lblTaste" for="txtTaste"></xp:label></xp:td>
            <xp:td>
                <xp:inputText id="txtTaste"><xp:this.value> <![CDATA[#{demo.fruitProperties["Taste"]}]]> </xp:this.value></xp:inputText></xp:td>
        </xp:tr>
        <xp:tr>
            <xp:td></xp:td>
            <xp:td>
                <xp:button value="Update" id="button1"><xp:eventHandler event="onclick" submit="true" refreshMode="complete" immediate="false" save="true"></xp:eventHandler></xp:button></xp:td>
        </xp:tr>
    </xp:table></xp:view>
 
As usual: YMMV

Posted by on 11 January 2011 | Comments (6) | categories: XPages

Comments

  1. posted by Nicola Senno on Tuesday 11 January 2011 AD:
    I like it a lot.
    Every thing goes smooth if you use POST method and a button, but
    I still have some issue passing params with in a url like:

    { Link }

    Should be the same GET/POST, at least in JSF2
  2. posted by Karsten Lehmann on Tuesday 11 January 2011 AD:
    And the real fun starts when you implement your own Map. The only method that JSF is looking at is the .get(String) method.
    Add code in there to read the submitted hash key and return a dynamically created value:

    public Object get(Object key) {
    String sKey=key.toString();

    String parts=sKey.split("#");
    String name=parts[0];
    String language=parts[1];

    Map localizedValues=valuesByLanguage.get(language);
    String localizedData=localizedValues.get(name);
    return localizedData;
    }
  3. posted by David Leedy on Tuesday 11 January 2011 AD:
    Great post Stephan. Having played with custom SSJS "Objects" I'm really interested in attempting to use managed beans. Just haven't really tried yet.

    If anyone seeing this is interested in more info.. Jeremy Hodge talked about this technique as well in a 3 part video series on NotesIn9 called "Introduction to Java". This can be found either at NotesIn9 or more easily on { Link }

    I really think Java knowledge is going to be required to make the most out of XPages.

  4. posted by vector on Wednesday 12 January 2011 AD:
    thanks for the help. greets Emoticon smile.gif
  5. posted by Patrick Kwinten on Wednesday 19 January 2011 AD:
    great reading! thanks for posting
  6. posted by Maksim on Wednesday 25 April 2012 AD:
    very nice atricle (though i'm a bit later)!
    there are some smaller typos in XPage #2...