【问题标题】:Adding custom attribute (HTML5) support to JSF 2.0 UIInput component向 JSF 2.0 UIInput 组件添加自定义属性 (HTML5) 支持
【发布时间】:2011-10-15 03:06:00
【问题描述】:

我正在尝试编写一个渲染器来处理<h:inputText> 组件上的placeholder 属性。 在阅读JSF 2.0 strips out needed HTML5 attributes 之后,我走向了这条路,这似乎是正确的。这是我的自定义渲染器

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

并且这个渲染器在 faces config 中注册为

 <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属性,插入它,然后将处理委托给super。我上面的代码不起作用,因为我在错误的地方插入了属性。它必须在writer.startElement('input') 执行后插入。但是,startElement 必须发生在 super 的 encodeBegin() 方法中的某处。那么如何插入自定义属性(本例中为“占位符”)然后继续执行流程?

注意:上面的代码确实添加了一个placeholder 属性,但没有添加到我打算添加的输入组件中,它会将其写入 Input 的父级(因为我试图在组件本身之前写入属性实际写在流中,它将属性应用到当前组件)

【问题讨论】:

    标签: html jsf jsf-2 mojarra


    【解决方案1】:

    这是我的方式。我添加了占位符和数据主题属性。如果要添加更多属性,只需将其名称添加到属性数组即可。

    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>
    

    【讨论】:

    • 这是迄今为止最实用最好的答案! :)
    • 感谢您的回复,虽然这是一个公平的答案,但代码有一个错误。 get(attribute) 的返回是一个对象,它可能是一个布尔值(例如考虑required 属性)。完全删除 (String) 强制转换并将返回类型设置为 Object。
    • 请注意,这不适用于 &lt;h:panelGrid&gt; 父级和 &lt;h:inputText&gt; 子级。 JSF 将required 属性放在&lt;td&gt; 元素中,而不是&lt;input&gt; 元素中。我说过我喜欢 JSF 吗?
    • @DarrellTeague 当 inputText 是 div 的子元素时,它还会将占位符放入 div 元素。有没有办法解决这个问题?
    • 这是非常有用的信息。省去了视图方面的很多麻烦,而且极其简单。
    【解决方案2】:

    你可以重写 ResponseWriters 的 startElement 方法,该方法只被调用一次,然后你可以恢复到原来的 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.
        }
    
    
    
    }
    

    【讨论】:

    • 上述效果更好(虽然缺少一些导入,但我更正了 getWrapped() ,因为 JSF 1.2 现在是公开的,等等)。我认为这是最好的答案。使用 if ("constant".equals(value)) 作为处理空值检查的方法可能更好,因为常量永远不会等于空值,但不会抛出 NPE。我现在正式鄙视 JSF 的卷积作为一种更好的选择,但感谢这里所有的良好反馈(感谢 Joel 支持 StackOverflow)。
    【解决方案3】:

    并覆盖 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");
        }
    
        }
    }
    

    【讨论】:

    • 对于那些阅读速度太快的人,您还需要在 faces-config.xml 文件中添加上面的 标签。
    猜你喜欢
    • 2013-03-12
    • 2012-05-21
    • 2015-07-15
    • 2017-11-07
    • 2011-07-01
    • 2014-05-29
    • 1970-01-01
    • 2021-12-05
    • 2015-01-02
    相关资源
    最近更新 更多