2015-08-25 70 views
1

Mojarra 2.1如何檢測validator中的valueChange事件?

我需要爲h:inputText寫一個驗證器,它只有在該輸入值改變時纔會執行一些邏輯。即

public class MyValidator implements Validator{ 

    public void validate(FacesContext context, 
         UIComponent component, 
         Object value) throws ValidatorException; 
     if(valueChanged(UIComponent component)){ //The method checks if the value's changed 
       //do some piece of logic 
     } 
     return; 
    } 
} 

我挖成UIInput的排隊事件和發現這一點:

validateValue(context, newValue); 

// If our value is valid, store the new value, erase the 
// "submitted" value, and emit a ValueChangeEvent if appropriate 
if (isValid()) { 
     Object previous = getValue(); 
     setValue(newValue); 
     setSubmittedValue(null); 
     if (compareValues(previous, newValue)) { 
      queueEvent(new ValueChangeEvent(this, previous, newValue)); 
     } 
    } 

這段代碼是從所述方法中,通過驗證階段回調執行。首先想到的是查詢處理請求期間發生的所有事件。該方法queueEvent(FacesEvent)被實現如下:

public void queueEvent(FacesEvent event) { 

    if (event == null) { 
     throw new NullPointerException(); 
    } 
    UIComponent parent = getParent(); 
    if (parent == null) { 
     throw new IllegalStateException(); 
    } else { 
     parent.queueEvent(event); 
    } 

} 

因此每一個這樣的invokation將在UIViewRoot.queueEvent(FacesEvent)最終成爲被實現:

public void queueEvent(FacesEvent event) { 

    if (event == null) { 
     throw new NullPointerException(); 
    } 
    // We are a UIViewRoot, so no need to check for the ISE 
    if (events == null) { 
     int len = PhaseId.VALUES.size(); 
     List<List<FacesEvent>> events = new ArrayList<List<FacesEvent>>(len); 
     for (int i = 0; i < len; i++) { 
      events.add(new ArrayList<FacesEvent>(5)); 
     } 
     this.events = events; 
    } 
    events.get(event.getPhaseId().getOrdinal()).add(event); 
} 

這意味着,所有事件實際上是作爲一個List<List<FacesEvent>>每個階段期間存儲。但List<List<FacesEvent>> events是一個私人領域,所以它不可能直接訪問它。

另一件事是在quingEvent之前正在進行實際驗證,因此實施valueChangeListener似乎也不太有用。

問題:是否有可能在一個自然的方式以實現在JSF這樣的驗證?

回答

1

只要做自己的價值比較。在驗證器中,舊值只需通過UIComponent參數即可獲得。

@Override 
public void validate(FacesContext context, UIComponent component, Object submittedValue) { 
    if (component instanceof EditableValueHolder) { 
     Object newValue = submittedValue; 
     Object oldValue = ((EditableValueHolder) component).getValue(); 

     if (newValue == null ? oldValue == null : newValue.equals(oldValue)) { 
      return; // Not changed, so skip validation. 
     } 
    } 

    // Do actual validation here. 
} 

如果你碰巧使用JSF工具庫OmniFaces,它有一個ValueChangeValidator這正是這一點。

+0

再澄清一點:'getValue()'方法直接從解碼的'ViewState'中獲取值? –

+0

這部分基本上回答在http://stackoverflow.com/questions/31955955/understanding-jsf-components-class-lifetime/31958332#31958332所以,只有當本地值設置(即以前提交的值沒有使它更新模型值階段),它基本上從視圖狀態中抓取。 – BalusC