Dynamically adding components to a custom composite JSF component

When writing a custom JSF component, you might want to include other components in yours. JSF provides different ways to achieve this, the hard way is to encode-decode the other component you want to include. The easy way is to create and add the component programatically you want to include, to your composite component. For example you want to add a input text component dynamically.

private void encodeInputText(FacesContext context) {
     
HtmlInputText inputText = new HtmlInputText();
      inputText.setParent(this);
      inputText.setId(this.getId() + “:_text1”);
      inputText.encodeBegin(context);
      inputText.encodeEnd(context);

}

This code will render an input text to the page, in this example you can also manipulate several properties of the inputText before calling encode, you can set converters, validators, style classes, and other component specific attributes to inputText here without coding html. Calling encode will give this job to the renderer of the inputText.

This was a simple example, if the component being added dynamically renders it’s children you should also check for the getRendersChildren() of the component and call encodeChildren if necessary. I’ve tried the code above many times and did not have any problem, however there seems to be a better alternative to this, an opposite way actually, using

getChildren().add(the_component_to_be_added);

Updated: After adding the child component dynamically, like the first way, the encoding methods must be called in order to render the children.

4 Responses to Dynamically adding components to a custom composite JSF component

  1. ScaryFox says:

    Hi,

    I’m looking into including your code guidelines into a project, but cannot seem to make it work. Could you give me aclue please?

    I’m trying to dynamically add a children element, a standard commandLink component from jsf framework, but the action binding refuses to work …

    I’ve created a custom jsf component, that does nothing at all.

    For example, one would use it like:

    <my:nothing></my:nothing>
    

    So my UI component class would have the following methods:

    public void encodeBegin(FacesContext context) throws IOException {
    }
    public void encodeEnd(FacesContext context) throws IOException {
    }
    

    The tld file is created, the tag class is working. All the component is working properly.

    Now I want to add a link as a child component, but I wat to do it programatically, so I changed the encodeBegin method of my custom ui class:

    import javax.faces.el.ValueBinding;
    import com.sun.faces.util.Util;
    import javax.faces.el.MethodBinding;
    import javax.faces.component.UICommand;
    import javax.faces.component.html.HtmlCommandLink;
    import com.sun.faces.taglib.html_basic.CommandLinkTag;
    (...)
    
    public void encodeBegin(FacesContext context) throws IOException {
    		String myLinkId = "idMyLink";
    		String myLinkValue = "myLink:Value";
    		String myLinkStyle = "color:green;";
    		String myLinkAction = "backup";
    		HtmlCommandLink myLink = new HtmlCommandLink();
    		myLink.setParent(this);
    		myLink.setId( myLinkId );
    		if (CommandLinkTag.isValueReference( myLinkValue )) {
    			ValueBinding vb = Util.getValueBinding( myLinkValue );
    			myLink.setValueBinding("value", vb);
    		} else {
    			myLink.setValue( myLinkValue );
    		}
    		if (CommandLinkTag.isValueReference( myLinkStyle )) {
    			ValueBinding vb = Util.getValueBinding( myLinkStyle );
    			myLink.setValueBinding("style", vb);
    		} else {
    			myLink.setStyle( myLinkStyle );
    		}
    		if(myLinkAction!=null) {
    			if (CommandLinkTag.isValueReference( myLinkAction )) {
    				System.err.println("Id="+myLinkId+":TRUE:getAccao:isValueReference:"+myLinkAction);
    				MethodBinding vb = getFacesContext().getApplication().createMethodBinding(myLinkAction, null);
    				myLink.setAction(vb);
    			} else {
    				System.err.println("Id="+myLinkId+":FALSE:getAccao:isValueReference:"+myLinkAction);
    				final String outcome = cNfo.getAccao();
    				MethodBinding vb = Util.createConstantMethodBinding( myLinkAction );
    				myLink.setAction(vb);
    			}
    		}
    		myLink.encodeBegin(getFacesContext());
    		myLink.encodeEnd(getFacesContext());
    }
    

    This seems to work, but not quite … the link appears as expected, the value references for value and style are correctly passed, but the action doesn’t work at all.

    For example if I change to:

    String myLinkValue = "#{mybean.linkText}";

    And I have the following method created on my managed bean:

    	public String getLinkText() {
    		return "This is myLink Text!";
    	}
    

    Is successfully calls and retrieves the value from the method. Same happens to the style property.

    Now for the action, if I change to:

    String myLinkAction = "#{mybean.doMyLinkAction}";

    And I have the following method created on my managed bean:

    	public String doMyLinkAction() {
    		return "backup";
    	}
    

    The result is nothing … I mean the method is not called at all. The “backup” is properly defined on my “faces-config.xml”:

       <navigation-rule>
          <from-view-id>/testPage.jsp</from-view-id>
          <navigation-case>
             <from-outcome>yes</from-outcome>
             <to-view-id>/yes.jsp</to-view-id>
          </navigation-case>
          <navigation-case>
             <from-outcome>no</from-outcome>
             <to-view-id>/no.jsp</to-view-id>
          </navigation-case>
          <navigation-case>
             <from-outcome>backup</from-outcome>
             <to-view-id>/backup.jsp</to-view-id>
          </navigation-case>
       </navigation-rule>
    

    If I create the link manually on the web page:

    <h:commandLink id="myLinkManual" value="Manually Created Link" style="" action="#{mybean.doMyLinkAction}"/>
    

    It does work (the backup.jsp page is shown), so the methods are properly configured, only the action binding does not work.

    Wether I use a string “backup” or a reference “#{mybean.doMyLinkAction}” I cannot make it work.

    On the console I get the following results, for each value I test (string “backup” or reference “#{mybean.doMyLinkAction}”):

    Id=idMyLink:TRUE:getAccao:isValueReference:backup
    Id=idMyLink:FALSE:getAccao:isValueReference:#{mybean.doMyLinkAction}
    

    So the “if (CommandLinkTag.isValueReference( myLinkAction )) {” is working properly … that just leaves me with the action method binding instructions …

    Why don’t they work?

    Any Help Appreciated … Thanks in Advance!

  2. Steve says:

    I dunno how you did it, I tried the getChildren().add() approach and nothing at all gets rendered. It’s extremely frustrating to read all over the place that it’s really easy to implement your own JSF composite components when in fact it plainly isn’t.

    I’ve no idea what I’m doing wrong!

  3. Cagatay says:

    How about the first approach? Also it is known that dynamically added components will not “behave” as you may expect.

  4. Anonymous says:

    defrert

%d bloggers like this: