Weblog

Creating a jsf div component

While creating a prototype for a web application using ADF Faces i noticed that Oracle’s JSF implementation still generates Html like it’s 1999. Lots of tables, more tables and more nested tables. ADF Faces even contains an ObjectSpacer component which adds a transparent image in your page. Ough. Big ugly mess.

The problem with tables is, apart from the fact that your pages will be bigger than necessary, that they’re pretty rigid. You don’t have a lot of positioning flexibility when creating the appearance of your page. This flexibility is pretty important when creating web application. Companies want their web applications to look good, not standard, when they are used by the outside world.

I started with the PanelPage component to layout the major parts of the page but because of the tables i could not get the required page design. I tried some other ADF Faces components, but didn’t find what i needed. PanelBox generates a single cell table. PanelHeader was the best i could find. It puts all it’s children in a div, but also generates an unwanted header tag.

What are the alternatives? I could use an html div tag or look for a JSF div component elsewhere (i think the MyFaces project contains a Div component). But instead, to learn a bit more about JSF, i decided to implement a custom Div component. I another post i’ll describe another alternative, a customer renderer for an existing component.

Div Component

The JSF component class contains the behaviour of your class. You can include the html rendering, but it’s cleaner to put that in a separate class. A panel doesn’t have a lot of behaviour as you can see in the following code. I’m subclassing UIPanel because it has the same behaviour as the Div component i want to implement.

package nl.iteye.jsf.components;

import javax.faces.component.UIPanel;

public class UIDiv extends UIPanel {
    public static final String COMPONENT_TYPE = "nl.iteye.jsf.Panel";
    public static final String RENDERER_TYPE = "nl.iteye.jsf.Div";

    public UIDiv() {
        setRendererType(RENDERER_TYPE);
    }

}

Div Renderer

The renderer creates the required html code. It is also used to read anything send by the browser, but that’s not needed in this case.

package nl.iteye.jsf.components;

import java.io.IOException;

import javax.faces.component.UIComponent;
import javax.faces.context.FacesContext;
import javax.faces.context.ResponseWriter;
import javax.faces.render.Renderer;

public class DivRenderer extends Renderer {
    public DivRenderer() {
    }

    public void encodeBegin(FacesContext context,
                            UIComponent component) throws IOException {
        ResponseWriter writer = context.getResponseWriter();
        writer.startElement("div", component);
        writer.writeAttribute("id", component.getClientId(context),
                              "clientId");
        writer.writeAttribute("class",
                              component.getAttributes().get("styleclass"),
                              "styleclass");
        writer.flush();
    }

    public void encodeEnd(FacesContext context,
                          UIComponent component) throws IOException {
        ResponseWriter writer = context.getResponseWriter();
        writer.endElement("div");
        writer.flush();
    }

    public void decode(FacesContext context, UIComponent component) {
        return;
    }
}

Div Tag

Next i need to create a JSP tag class, because i’m going to use the JSF component in JSPs. A property for id is not needed, this is provided by the super class.

package nl.iteye.jsf.components;

import javax.faces.component.UIComponent;
import javax.faces.context.FacesContext;
import javax.faces.webapp.UIComponentTag;

public class DivTag extends UIComponentTag {
    private String styleClass;

    public DivTag() {
    }

    public String getComponentType() {
        return UIDiv.COMPONENT_TYPE;
    }

    public String getRendererType() {
        return UIDiv.RENDERER_TYPE;
    }

    public void setProperties(UIComponent component) {
        super.setProperties(component);
        setStringProperty(component, "styleclass", styleClass);
    }

    public void setStyleclass(String styleClass) {
        this.styleClass = styleClass;
    }

    public String getStyleclass() {
        return styleClass;
    }

    private void setStringProperty(UIComponent component, String name,
                                   String value) {
        if (value == null) {
            return;
        }
        if (isValueReference(value)) {
            component.setValueBinding(name,
                                      FacesContext.getCurrentInstance().getApplication()
                                      .createValueBinding(value));
        } else {
            component.getAttributes().put(name, value);
        }
    }
}

Configuration

Declare the component in the faces configuration file faces-config.xml. Two entries are required, one for the component, and one for the render-kit. A render-kit isn’t specified, which means that the renderer will be part of the default html renderkit.

  <component>
    <component-type>nl.iteye.jsf.Panel</component-type>
    <component-class>nl.iteye.jsf.components.UIDiv</component-class>
  </component>
  <render-kit>
    <renderer>
      <component-family>javax.faces.Panel</component-family>
      <renderer-type>nl.iteye.jsf.Div</renderer-type>
      <renderer-class>nl.iteye.jsf.components.DivRenderer</renderer-class>
    </renderer>
  </render-kit>

Register the Div tag in the tag library file:

<?xml version = '1.0' encoding = 'UTF-8'?>
<!DOCTYPE taglib
  PUBLIC "-//Sun Microsystems, Inc.//DTD JSP Tag Library 1.2//EN"
  "http://java.sun.com/dtd/web-jsptaglibrary_1_2.dtd">
<taglib>
  <tlib-version>1.0</tlib-version>
  <jsp-version>2.0</jsp-version>
  <short-name>jsf-layout</short-name>
  <uri>/iteye/jsf</uri>
  <display-name>Layout components</display-name>
  <tag>
    <name>div</name>
    <tag-class>nl.iteye.jsf.components.DivTag</tag-class>
    <attribute>
      <name>id</name>
    </attribute>
    <attribute>
      <name>styleclass</name>
    </attribute>
  </tag>
</taglib>

Example

The following code shows a simple example. Normally i would use an id attribute instead of a class attribute in the example below, because you only have one header and one logo on every page. Unfortunately, JFS makes the id attribute unusable for css styling purposes, as it prepends the ids of all the parent components to the id of a component.

<?xml version='1.0' encoding='UTF-8'?>
<jsp:root xmlns="http://www.w3.org/1999/xhtml"
          xmlns:jsp="http://java.sun.com/JSP/Page" version="2.0"
          xmlns:h="http://java.sun.com/jsf/html"
          xmlns:f="http://java.sun.com/jsf/core"
          xmlns:af="http://xmlns.oracle.com/adf/faces"
          xmlns:wt="/iteye/jsf">
  <f:view>
    <html>
      <body>
        <h:form>
          <wt:div styleclass="page">
            <wt:div styleclass="header">
              <wt:div styleclass="logo">
                <af:objectImage source="/images/logo.gif"/>
              </wt:div>
            </wt:div>
          </wt:div>
        </h:form>
      </body>
    </html>
  </f:view>
</jsp:root>

This is not fastest way to create divs using JSF, but still usefull as an example of how to create a JSF component. As said before, you can just use a html div tag (for an interesting discussing about using html tags, see Chris Schalk’s weblog: JSF: Getting the Right Mixture of Components and Markup), but using html may be a problem when you decide to use a non html render kit. If you don’t need a new component, just different markup, a better option is to create a new renderer.

Update:
See the followup posts: JSF productivity, and IDE productivity for JSF: a screencast.

Share and Enjoy:
  • del.icio.us
  • Google Bookmarks
  • DZone
  • LinkedIn
  • SphereIt
  • StumbleUpon
  • Technorati

25 Responses to “Creating a jsf div component”

  1. Steven Says:

    You seem to be missing a closing wt:div in that last section.

    Seems like alot of work to just get a div.

  2. Andrej Koelewijn Says:

    Thanks, i’ve updated the code. I agree, it is a lot of work, just using html is easier. But it is a good example to show what’s involved in created a minimal jsf component. I think modifing the renderer of an existing component makes more sense: less work, and because you use jsf components you can still use a non html renderkit if you want to. It doesn’t tie your solution to html.

  3. Viliam Says:

    Why are tables bad? Only because they are old? Some time ago, I tried not to use tables but divs, and it’s support was not very good: several css rules did not work or worked diferently in various browsers – very general statement, but this was my impression: tables are reliable and work in old browsers. What’s bad with them?

  4. Andrej Says:

    - tables are rigid, you can’t move tables cell around the page like you can with divs.
    - tables require more markup than divs, your pages will be larger than necessary and harder to maintain.
    - tables can be confusion for screenreaders, what is tabular data, what is layout?
    - using divs it’s easier to create printable pages. Just hide the divs that don’t need to be printed.
    - using divs it’s easier to create pages for different screensizes. Need to display you page on a mobile phone? Just place the divs vertically.

  5. Viliam Says:

    Andrej, you convinced me. Only the compatibility remains an issue, I think. Compatibility between current browsers and compatibility with archaic browsers.

  6. Andrej Koelewijn Says:

    Dan Cederholm has written an excellent book called Bulletproof Web Design. He explains how to use css while ensuring that it will work in most browsers.

  7. Seth Thomas Rasmussen Says:

    Compatibility is almost a non-issue if you know a few tricks for dealing with IE. Other modern browsers have their quirks(almost always with workarounds), but often you can safely ignore certain fringe percentages anyway.

    If you’re so unfortunate as to have to deal with Netscape 4 or older such UAs, well.. find the person demanding this, explain that browser upgrades are free and fairly quick to install, and then punch them in the face.

  8. mush Says:

    OK…Been studying JSFs for a week now,and it seems that the ONLY way to implement a custom component is to code it directly into a class. This is a bit ugly: if (when) this component gets complicated, you end up with loads of write.startElement stuff….How the hell can you see the actual html structure from that??? There was an attempt to work around this by Hans Bergsten, quote: “…using XML file to represent the component structure and a separate pure HTML file as a template, binding the JSF components in the XML file to the corresponding HTML elements in the template with the help of id attributes.”.
    Is there any other way to do this? I’d like to see something like this: declare MyCustomComponent.jsf as a custom component, including it into a taglib, thus enabling to reuse it…Maybe you guessed I was inspired by the .NET framework, which uses similar model, which is, by the way, very simple and powerfull. I expected to find something similar in JSF but no such luck so far…Any ideas?
    tnx

  9. Andrej Koelewijn Says:

    I agree that coding the html in the java code is pretty ugly, and hard to maintain. Have you looked at facelets?

  10. The Peninsula’s Edge » JSF: HTML div and ul tags Says:

    [...] device. Andrej Koelewijn of IT-eye fame wrote an article discussing this issue and in his article provi [...]

  11. drysen Says:

    hello, i’m new in JFS, and i need div tag in my code, would you please tell me how to deploy this code so i can use in my IDE, i’m using Sun Studio Creator

  12. Andrej Koelewijn Says:

    This div component cannot be used in Sun Studio Creator, it misses some methods that tell the IDE how to use it. Maybe you can use Apache MyFaces, this JSF implementation also includes a div component.

  13. Nicolas Lang Says:

    Hello Andrej, I’m using JSF with Oracle 9, jdeveloper 10.1.3.1.0, toplink, Spring, and to follow the graphics rules I have to use a div tag in my jsf pages. I’m using some subview and I can’t have a good display with verbatim. My question is : Can i use your code or Is it more appropriate If i use tobago myfaces?
    Thanks

  14. Andrej Koelewijn Says:

    You’re free to use the code above, not sure if tobago will solve your issue. I looked through the components list, but didn’t see a div component.

  15. nikita Says:

    doesn’t h:panelGroup render as a div?

  16. Andrej Koelewijn Says:

    I believe the panelGroup component doesn’t create divs, it creates spans, and only if you provide it with an attribute. Otherwise it doesn’t write out the span tag.

  17. atiktepika Says:

    I’m using rational (websphere), anyone knows why I must to insert the div tag inside a form tag? I can’t use them whihout a form tag? Thanks for all.

  18. Miroslav Nachev Says:

    Here is written that with DIV is possible to be created so good looking Web UI Components (Table) like SwingX (http://www.swinglabs.org/) components. Unfortunately I am not meet such components until now.
    If there are, can you give me some URL (link)?

  19. Salman Says:

    @ atiktepika, I my limited experience with JSF, I have learned that there should always be a form inside the body of the page that JSF would render as HTML. Further more, both the div and form tags are “container” tags in terms of valid HTML structures divs should not be nested in a form tag.

  20. Jeremy Says:

    Hi I am having trouble getting the div to render as a div? I have built a very simple project following the steps above but when the page renders the output is not as expected

    Here is what you would expect
    Hello World
    I get this
    Hello Wolrd

    Any thoughts? I am using thin in an ADF Faces app would that make a difference?

  21. Jeremy Says:

    Last comment dropped the source that I tried to include, anyway the output is rendered exactly as it is in the JSF wt:Div page rather than as a simple HTML div

  22. Hari Gangadharan Says:

    Good writeup. But each framework has one or another way to render a div but div cannot be rendered in plain JSF-RI. In RichFaces / A4J you can use a4j:outputPanel with layout=”block”. Using ADF is the worst thing you can do… I am stuck with ADF for our main UI app. But in ADF also you can create a DIV using . I love JSF + facelet + Richfaces + jQuery – that is the best stack you can have!

    Hari Gangadharan

  23. Hari Gangadharan Says:

    Sucks! they stipped my adf code… I mean in ADF you can render a div using af:panelGroup with layout=”vertical”.

  24. JSF sucks « Incremental Operations Says:

    [...] Creating a jsf div component – blog post by Andrej Koelewijn. The amount of code and effort that is required for just [...]

  25. Hari Gangadharan Says:

    A blanket comment that “JSF sucks” makes me ask “compared to what?”. At the present time JSF may be one of the best Web UI environments in *Java*. But JSF without Facelets is inadequate. If you have facelets you can do all the layout/formatting in Facelets. JSF+RichFaces+jQuery is one of the best environments.

    Hari Gangadharan

Leave a Reply

Technology