Добавление поддержки пользовательских атрибутов (HTML5) в компонент JSF 2.0 UIInput

Я пытаюсь написать средство визуализации, которое будет обрабатывать атрибут placeholder компонента <h:inputText>. Я направился по этому пути после прочтения JSF 2.0 удаляет необходимые атрибуты HTML5 и вроде правильно. Вот мой пользовательский рендерер

public class InputRenderer extends com.sun.faces.renderkit.html_basic.TextRenderer{

    @Override
    public void encodeBegin(FacesContext context, UIComponent component) 
    throws IOException {
        System.out.println("Rendering :"+component.getClientId());

        String placeholder = (String)component.getAttributes().get("placeholder");
        if(placeholder != null) { 
            ResponseWriter writer = context.getResponseWriter();
            writer.writeAttribute("placeholder", placeholder, "placeholder");
        }

        super.encodeBegin(context, component);

    }


    @Override
    public void decode(FacesContext context, UIComponent component) {
        super.decode(context, component);
    }

    @Override
    public void encodeEnd(FacesContext context, UIComponent component) 
    throws IOException {
        super.encodeEnd(context, component);
    }
}

И этот рендер прописан в конфиге лиц как

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

Это регистрируется нормально, никаких проблем.

Мое намерение состоит в том, чтобы обработать атрибут placeholder, вставить его, а затем делегировать обработку супер. Мой приведенный выше код не работает, потому что я вставляю атрибут не в то место. Он должен быть вставлен после выполнения writer.startElement('input'). Однако startElement должен происходить где-то в методе super encodeBegin(). Итак, как мне вставить настраиваемый атрибут (в данном случае «заполнитель»), а затем продолжить выполнение?

NB: приведенный выше код добавляет атрибут placeholder, но не к входному компоненту, который я намереваюсь сделать, он записывает его в родительский элемент ввода (поскольку я пытаюсь написать атрибут до того, как сам компонент будет фактически записан в потоке , он применяет атрибут к текущему компоненту)


person Niks    schedule 28.07.2011    source источник


Ответы (3)


Это мой путь. Я добавил атрибуты заполнителя и темы данных. Если вы хотите добавить больше атрибутов, вы должны просто добавить его имя в массив атрибутов.

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);

    }

}

Вы должны добавить это в файлfaces-config.xml.

 <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>
person mb.akturk    schedule 10.07.2012
comment
Это, безусловно, самый практичный и лучший ответ! :) - person Niks; 07.11.2012
comment
Спасибо за ответ, и хотя это честный ответ, в коде есть ошибка. Возврат get(attribute) — это объект, который может быть логическим значением (например, рассмотрим атрибут required). Полностью удалите приведение (String) и установите возвращаемый тип как Object. - person Darrell Teague; 21.01.2013
comment
Обратите внимание, что это не работает с <h:panelGrid> родителем с <h:inputText> дочерними элементами. JSF помещает атрибут required в элемент <td> вместо элемента <input>. Я говорил, что люблю JSF? - person Darrell Teague; 21.01.2013
comment
@DarrellTeague Он также помещает заполнитель в элемент div, когда inputText является дочерним элементом div. Есть ли способ решить эту проблему? - person cubbuk; 23.01.2013
comment
Это была чрезвычайно полезная информация. Это избавляет от многих головных болей со стороны просмотра и чрезвычайно просто. - person Daniel B. Chapman; 12.05.2013
comment
Лучший ответ, но я хочу знать, как сделать то же самое для пользовательского компонента ‹h:customComponen›, который объявлен внутри фасетов taglib.xml - person Sasi Dhivya; 06.06.2017

Вы можете просто переопределить метод startElement ResponseWriters, этот метод вызывается только один раз, а затем вы можете восстановить исходный объект responsewriter.

import javax.faces.context.*;
import java.io.IOException;

public class InputRenderer extends com.sun.faces.renderkit.html_basic.TextRenderer{

      // Put all of the attributes you want to render here...
      private static final String[] ATTRIBUTES = {"required","placeholder"};

    @Override
    protected void getEndTextToRender(FacesContext context,
            UIComponent component, String currentValue) throws IOException {
        final ResponseWriter originalResponseWriter = context.getResponseWriter();
        context.setResponseWriter(new ResponseWriterWrapper() {

            @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);
if ("input".equals(name)) {
  for (String attribute : ATTRIBUTES)
  {
    Object value = component.getAttributes().get(attribute);
    if (value != null)
    {
      super.writeAttribute(attribute,value,attribute);
} 
  }
}   
        });
        super.getEndTextToRender(context, component, currentValue);
        context.setResponseWriter(originalResponseWriter); // Restore original writer.
    }



}
person dileks    schedule 25.10.2011
comment
Вышеупомянутое работает лучше (хотя некоторые импорты отсутствуют, я исправил getWrapped(), так как в JSF 1.2 теперь общедоступен и т. д.). Я думаю, что это лучший ответ. Также, вероятно, лучше использовать if (constant.equals(value)), поскольку это обрабатывает проверку на нулевое значение, поскольку константа никогда не будет равна нулю, но не вызовет NPE. Теперь я официально презираю свертки JSF как лучшую альтернативу, но ценю все хорошие отзывы здесь (спасибо Джоэлу за поддержку StackOverflow). - person Darrell Teague; 01.02.2013

И переопределить для MyFaces 2.0.8+

package com.hsop.abc.eld;

import java.io.IOException;

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

import org.apache.myfaces.renderkit.html.HtmlTextRenderer;

public class InputRenderer extends HtmlTextRenderer
{
    @Override
    protected void renderInputBegin(FacesContext context, UIComponent component)
            throws IOException
    {
        // TODO Auto-generated method stub
        super.renderInputBegin(context, component);

    Object placeholder = component.getAttributes().get("placeholder");
    if(placeholder != null) { 
        ResponseWriter writer = context.getResponseWriter();
        writer.writeAttribute("placeholder", placeholder, "placeholder");
    }

    }
}
person Madhuri    schedule 13.12.2013
comment
Для тех, кто читает слишком быстро, вам также понадобится тег ‹render-kit›, приведенный выше, в файлеfaces-config.xml. - person Gustavo Ulises Arias Méndez; 15.04.2016