2011-07-28 81 views
11

我正在嘗試編寫一個將在<h:inputText>組件上處理placeholder屬性的呈示器。 我在閱讀JSF 2.0 strips out needed HTML5 attributes後走向了這條路,看起來正確。這裏是我的自定義渲染將自定義屬性(HTML5)支持添加到JSF 2.0 UIInput組件

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屬性,插入它,然後將處理委託給super。我上面的代碼不起作用,因爲我在錯誤的地方插入了屬性。必須在writer.startElement('input')執行後插入。但是,startElement必須在超級的encodeBegin()方法中發生。那麼如何插入一個自定義屬性(在這種情況下爲'placeholder'),然後繼續執行流程?

注意:上面的代碼確實會添加一個placeholder屬性,但不會添加到我打算輸入的組件中,它將它寫入Input的父級(因爲我試圖在組件本身實際進行寫入之前寫入屬性寫在流,它適用的屬性給當前的組件)

回答

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)轉換並將返回類型設置爲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

以上工作得更好(雖然缺少一些進口的,我糾正getWrapped()在JSF 1.2現在是公開的,等等)。我認爲這是最好的答案。它也可能更好地使用if(「常量」.equals(值))作爲處理空檢查,因爲常量永遠不會等於null,但不會拋出NPE。我現在正式鄙視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文件。 –