Primefaces render kit html5 attributes

Standard

When using JSF 2.0 / 2.1 the need for using passthrough elements may occur. However, the passthrough element library is not compatible until JSF 2.2. The following solution uses a custom renderer so that primefaces 5.x can implement HTML5 attributes that you define.

Define your attributes

This first class is use to define which attributes we want to be able to pass through. The static string attributes is the name of these attributes.

The method above called writeAttributes does exactly what means. It writes the attribute(s) pass on the UIComponent to the current facesContext. The attributes that it is checking for are those of which you have defined.

public final class Html5DataAttributes {

    public static void writeAttributes(FacesContext context, UIComponent component) throws IOException {

        ResponseWriter writer = context.getResponseWriter();

        for (String attribute : Html5DataAttributes.attributes) {
            String value = (String) component.getAttributes().get(attribute);
            if (value != null) {
                writer.writeAttribute(attribute, value, null);
            }
        }
    }

    public static String[] attributes = {
        "placeholder", "data-toggle"
    };
}

You can add as many attributes to the array as needed. Make sure the attributes you do add are not already apart of the primefaces existing component, otherwise the values would be rendered twice.

Create a inputText renderer

To utilize the class above it requires extending the InputTextRenderer class in Primefaces. By default you must override the encodeEnd method. This is where all the magic happens. The method starts by calling the Html5DataAttributes class above. That writes out our custom attributes, it then concludes by calling the classes super. That assures that the existing component attributes in Primefaces will still be rendered.

public class PfInputTextRenderer extends InputTextRenderer {

    @Override
    public void encodeEnd(FacesContext context, UIComponent component) throws IOException {

        Html5DataAttributes.writeAttributes(context, component);
        super.encodeEnd(context, component);
    }

}

It should be noted that this is specifically only for the p:inputText component. You can create more renderers as you need them. Ex: CommandButtonRenderer

Register the renderer class

The last step is to tell primefaces where the new render class is located. This is accomplished by places the following in your faces-config.xml.

<renderer>
    <component-family>org.primefaces.component</component-family>
    <renderer-type>org.primefaces.component.InputTextRenderer</renderer-type>
    <renderer-class>com.sixthpoint.renderers.PfInputTextRenderer</renderer-class>
</renderer>

The render-type is the base class that primefaces uses for rendering the component. The component-family is the location of all similar components. The render-class is the new class we have created to handle inputText rendering.

How do I use it?

It is pretty simple, when calling p:inputText specify your custom attribute

<p:inputText value="#{myBean.value}" placeholder="My custom attribute"/>

What is I have JSF 2.2? 

Then don’t waste your time on what was described above. You can use the built in passthrough library

<html xmlns="http://www.w3.org/1999/xhtml"
      xmlns:h="http://xmlns.jcp.org/jsf/html"
      xmlns:pass="http://xmlns.jcp.org/jsf/passthrough">
<h:body>
  <h:form id="form">
    <h:inputText value="#{myBean.value}" pass:placeholder="My placeholder"/>
  </h:form>
</h:body>
</html>

Read more on javadoc

HTML5 input type=”date” with javascript fallback

Standard

HTML5 brings great new features which will ease development. However, currently there is a gap between browsers that support HTML5 attributes and those who do not. As of October around 60% of desktop browsers and 80% of mobile devices are HTML5 compliant. This means developers still need support the additional 40% which fallback techniques.

HTML5 date input field

A good example is the new date input field. If your browser is HTML5 compliant it generate a date picker for you to use automatically, thus only requiring the developer to create the input field as so:

<input name="start_date" type="date" placeholder="mm/dd/yyyy" />

If the browser does not support HTML5 then no restriction on the date format will occur. This is why javascript is a beautiful tool.

Providing a fallback

Using a combination of Modernizr, jQuery, and bootstrap-datetimepicker javascript libraries a HTML5 date field can be emulated. Modernizr is a library use for feature detection. It can recognize if the HTML5 date object is available to the browser. If the date object is not available then the bootstrap-datetimepicker will bind to the input and provide a calendar for the user.

The following is the javascript which a datetime picker to the input field below if necessary.

$(document).ready(function () {
    // If they do not have HTML5 date then provide a datepicker using javascript
    if (!Modernizr.inputtypes.date) {
            
        $('#startDatetime').datetimepicker({
            pickDate: true,
            pickTime: false
        });
            
     }
});

The input field has classes attached that are from the bootstrap 3 library. These libraries add a hint of design to the end result.

<div class="input-group date" id="startDatetime">
   <input name="end_date" type="date" placeholder="mm/dd/yyyy" class="form-control"/>
   <span id="endDateIcon" class="input-group-addon">
      <span class="glyphicon glyphicon-calendar"></span>
   </span>
</div>

Note: In this example I used the bootstrap-datetimepicker library, however any javascript date picker may be substituted in its place. The following libraries were used: bootstrap3, modernizr, momentjs (required by bootstrap-datepicker), and jQuery 2.1.0.

A example of this project can be seen on JSFiddle.