Adding Custom Attribute (Html5) Support to Jsf 2.0 Uiinput Component

Adding custom attribute (HTML5) support to JSF 2.0 UIInput component

This is my way. I added placeholder and data-theme attributes. If you want to add more attributes, you should just add its name to attributes array.

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

import com.sun.faces.renderkit.html_basic.TextRenderer;

public class InputRender extends TextRenderer {

@Override
protected void getEndTextToRender(FacesContext context,
UIComponent component,
String currentValue)
throws java.io.IOException{

String [] attributes = {"placeholder","data-theme"};

ResponseWriter writer = context.getResponseWriter();

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

super.getEndTextToRender(context, component, currentValue);

}

}

You should add this to faces-config.xml file.

 <render-kit>
<renderer>
<component-family>javax.faces.Input</component-family>
<renderer-type>javax.faces.Text</renderer-type>
<renderer-class>your.package.InputRenderer</renderer-class>
</renderer>
</render-kit>

Adding custom attribute (HTML5) support to Primefaces (3.4)

Instead of homegrowing a custom renderer for every single individual component, you could also just create a single RenderKit wherein you provide a custom ResponseWriter wherein the startElement() method is overriden to check the element name and/or component instance and then write additional attributes accordingly.

Here's a kickoff example of the HTML5 render kit:

public class Html5RenderKit extends RenderKitWrapper {

private RenderKit wrapped;

public Html5RenderKit(RenderKit wrapped) {
this.wrapped = wrapped;
}

@Override
public ResponseWriter createResponseWriter(Writer writer, String contentTypeList, String characterEncoding) {
return new Html5ResponseWriter(super.createResponseWriter(writer, contentTypeList, characterEncoding));
}

@Override
public RenderKit getWrapped() {
return wrapped;
}

}

The HTML5 response writer:

public class Html5ResponseWriter extends ResponseWriterWrapper {

private static final String[] HTML5_INPUT_ATTRIBUTES = { "autofocus" };

private ResponseWriter wrapped;

public Html5ResponseWriter(ResponseWriter wrapped) {
this.wrapped = wrapped;
}

@Override
public ResponseWriter cloneWithWriter(Writer writer) {
return new Html5ResponseWriter(super.cloneWithWriter(writer));
}

@Override
public void startElement(String name, UIComponent component) throws IOException {
super.startElement(name, component);

if ("input".equals(name)) {
for (String attributeName : HTML5_INPUT_ATTRIBUTES) {
String attributeValue = component.getAttributes().get(attributeName);

if (attributeValue != null) {
super.writeAttribute(attributeName, attributeValue, null);
}
}
}
}

@Override
public ResponseWriter getWrapped() {
return wrapped;
}

}

To get it to run, create this HTML5 render kit factory:

public class Html5RenderKitFactory extends RenderKitFactory {

private RenderKitFactory wrapped;

public Html5RenderKitFactory(RenderKitFactory wrapped) {
this.wrapped = wrapped;
}

@Override
public void addRenderKit(String renderKitId, RenderKit renderKit) {
wrapped.addRenderKit(renderKitId, renderKit);
}

@Override
public RenderKit getRenderKit(FacesContext context, String renderKitId) {
RenderKit renderKit = wrapped.getRenderKit(context, renderKitId);
return (HTML_BASIC_RENDER_KIT.equals(renderKitId)) ? new Html5RenderKit(renderKit) : renderKit;
}

@Override
public Iterator<String> getRenderKitIds() {
return wrapped.getRenderKitIds();
}

}

And register it as follows in faces-config.xml:

<factory>
<render-kit-factory>com.example.Html5RenderKitFactory</render-kit-factory>
</factory>

The JSF utility library OmniFaces has also such a render kit, the Html5RenderKit (source code here) which should theoretically also work fine on PrimeFaces components. However, this question forced me to take a second look again and I was embarrassed to see that the component argument in ResponseWriter#startElement() is null in <p:inputText> (see line 74 of InputTextRenderer, it should have been writer.startElement("input", inputText) instead). I'm not sure if this is intentional or an oversight in the design of the PrimeFaces renderer or not, but you could use UIComponent#getCurrentComponent() instead to get it.


Update: this is fixed in OmniFaces 1.5.


Noted should be that the upcoming JSF 2.2 will support defining custom attributes in the view via the new passthrough namespace or the <f:passThroughAttribute> tag. See also What's new in JSF 2.2? - HTML5 Pass-through attributes.

Thus, so:

<html ... xmlns:p="http://java.sun.com/jsf/passthrough">
...
<h:inputText ... p:autofocus="true" />

(you may want to use a instead of p as namespace prefix to avoid clash with PrimeFaces' default namespace)

Or:

<h:inputText ...>
<f:passThroughAttribute name="autofocus" value="true" />
</h:inputText>

JSF 2.0 strips out needed HTML5 attributes

JSF isn't exactly stripping them out. It's just ignoring them because they are not among the supported/known attributes of the component in question. In case of for example <h:inputText> (which renders by default a HTML <input type="text"> tag), you can find all supported attributes in the view declaration language (VDL) documentation.

To overcome this, you would need to create a custom component or, better, just a custom renderer which overrides the standard <h:inputText> renderer and takes the custom attributes into account.

JSF Custom component attribute properties with Annotations

There isn't any annotation to do what you'd like.

If you don't know yet how to add attributes to your custom JSF components, you can look here : Adding custom attribute (HTML5) support to JSF 2.0 UIInput component

Add custom html attribute to be rendered for jsf2 component

There is no trivial way to achieve this. Unregistered attribtues are completely ignored. Assuming that you're using Mojarra, your best bet is to extend Mojarra's CheckboxRenderer with a custom one wherein you override the getEndTextToRender() method which writes the extra attribute. To get it to run, just register it in faces-config.xml as a renderer for component family javax.faces.SelectBoolean and renderer type javax.faces.Checkbox.

An alternative is to delegate the job to some onload JavaScript.

JSF removes custom HTML component attributes

You don't need to write your own tags, it is sufficient to write your own renderer for the JSF-tags. A renderer which does not omit your custom attributes.

Look here on how to write & configure such a renderer for all your inputs.

Adding bootstrap attribute to custom MenuRenderer in JSF

UPDATE II - ANSWER -
I chose a mixed approach between dilek's code and Vladiator's code. I just need to create one helper class called AditionalAttributesWritter. Also, is a good idea to check out the code implementation.

import java.io.IOException;

import javax.faces.component.UIComponent;
import javax.faces.context.ResponseWriter;
import javax.faces.context.ResponseWriterWrapper;

/**
* @link https://stackoverflow.com/a/7886942/4253946
*/
public class AditionalAttributesWritter extends ResponseWriterWrapper {
private static final String[] ATTRIBUTES = { "data-toggle" };
private ResponseWriter originalResponseWriter;

public AditionalAttributesWritter(ResponseWriter originalResponseWriter) {
super();
this.originalResponseWriter = originalResponseWriter;
}

@Override
// As of JSF 1.2 this method is now public.
public ResponseWriter getWrapped() {
return originalResponseWriter;
}

@Override
public void startElement(String name, UIComponent component) throws IOException {
super.startElement(name, component);
for (String attribute : ATTRIBUTES) {
Object value = component.getAttributes().get(attribute);
if (value != null) {
super.writeAttribute(attribute, value, attribute);
}
}
}
}

and finally the SelectRenderer is like this

import com.sun.faces.renderkit.html_basic.MenuRenderer;

import java.io.IOException;

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

/**
* @link https://stackoverflow.com/questions/27324024/jsf-selectonemenu-extending-menurenderer-for-displaying-a-plain-text-when-there/27337240#27337240
*/
public class SelectRenderer extends MenuRenderer {
@Override
protected void renderSelect(FacesContext context, UIComponent component) throws IOException {
final ResponseWriter originalResponseWriter = context.getResponseWriter();
context.setResponseWriter(new AditionalAttributesWritter(originalResponseWriter));
super.renderSelect(context, component);
context.setResponseWriter(originalResponseWriter); // Restore original writer.
}
}

and it works. If you think that this approach is not good enough please let me know.

How to add placeholder attribute to JSF input component?

I thought everything that was not JSF was passed to the browswer for rendering?

This assumption is thus wrong. Unspecified component attributes are ignored by the JSF renderers.

You have basically the following options to get it to work:

  1. If you're already on JSF 2.2 or newer, set it as a passthrough attribute.

     <... xmlns:a="http://xmlns.jcp.org/jsf/passthrough">

    <h:inputText a:placeholder="fill me" />

    Note that I use a XML namespace prefix of a ("attribute") instead of p as shown in the tutorial, as it would otherwise clash with default XML namespace prefix p of PrimeFaces.

  2. Implement a custom renderer for <h:inputText> wherein you explicitly check and write the attribute.

  3. Implement a custom component which uses the aforementioned custom renderer.

  4. Implement a JS based solution wherein you grab the element from DOM and explicitly set the attribute.

  5. Look for a component library which supports this out the box. PrimeFaces for example has a <p:watermark> for this purpose with nice JS based graceful degradation for browsers which does not support the placeholder attribute on inputs.

See also:

  • Custom HTML tag attributes are not rendered by JSF


Related Topics



Leave a reply



Submit