2011-07-28 16 views
11

<h:inputText>コンポーネントのplaceholder属性を処理するレンダラーを作成しようとしています。 JSF 2.0 strips out needed HTML5 attributesを読んだ後、私はこの道に向かいましたが、それは正しいようです。ここに私のカスタムレンダラはJSF 2.0 UIInputコンポーネントへのカスタム属性(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はスーパーのencodeBegin()メソッドのどこかで発生している必要があります。では、カスタム属性(この場合は「プレースホルダ」)を挿入して実行フローを続行するにはどうすればよいですか?

NB:上記のコードは、私が意図する入力コンポーネントにはplaceholder属性を追加しません。入力の親に書き込みます(実際にはコンポーネント自体が実際に作成される前に属性を書き込もうとしています)。現在のコンポーネントに属性を適用します)。

答えて

19

これは私の方法です。プレースホルダとデータテーマの属性を追加しました。さらに属性を追加したい場合は、その名前を属性配列に追加するだけです。

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> 
+0

これははるかに実用的で最良の答えです! :) – Nikhil

+1

お返事ありがとうございます。これは公平な回答ですが、コードにはバグがあります。 get(attribute)の戻り値はObjectであり、これはブール値(例えば 'required'属性を考慮する)です。 (String)キャストを完全に削除し、return-typeをObjectとして設定します。 –

+1

これは ''親と ''子では機能しません。 JSFは ' '要素の代わりに'​​'要素に' required'属性を置きます。私はJSFが好きですか? –

6

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. 
    } 



} 
+0

のために無効にするには良い作品(一部輸入品が不足していますが、私は、JSF 1.2のように)(getWrappedを修正など、今公開されて)。私はこれが最高の答えだと思います。定数がnullにはならず、NPEを投げないので、nullチェックを処理するif( "constant" .equals(value))を使用する方がよいでしょう。私は今や正式にJSFのコンボリューションを軽視していますが、ここで良いフィードバックをいただければ幸いです(JoelがStackOverflowをサポートしてくれたことに感謝します)。 –

2

そして、上記の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"); 
    } 

    } 
} 
+0

あまりにも速い人は、タグが必要ですfaces-config.xmlファイル。 –

関連する問題