2010-03-18 65 views
1

我遇到問題。在PhaseListener中修改JSF組件樹

我已經實現了一個PhaseListener,它意味着將一個樣式類添加到樹中有消息附加到它們的任何UIInput組件,並刪除樣式類,如果它沒有附加任何消息。

PhaseListener在RENDER_RESPONSE階段運行,並且在調試時在beforePhase和afterPhase方法中都可以工作。在調試時,我發現beforePhase不能訪問完整的組件樹,但afterPhase會。 afterPhase中所做的任何更改都不會呈現。

我該如何解決這個問題?我希望這完全是服務器端。

感謝,

詹姆斯

回答

0

使用的ViewHandler實現,但它的效率不高。渲染響應階段的PhaseListener無權訪問組件樹。

2

JSF組件樹僅在視圖構建時間後纔可用。在呈現之前,RENDER_RESPONSE階段不一定是訪問完整JSF組件樹的好時機。在沒有任何<f:viewAction>的初始GET請求期間,完整組件樹僅在afterPhase中可用,因爲它在RENDER_RESPONSE期間正在構建。在回發期間,完整的組件樹在beforePhase中可用,但是,當導航到不同的視圖時,它將在RENDER_RESPONSE階段改變,所以任何修改都會丟失。

要了解準確的觀點構建時間是什麼,頭問題What's the view build time?

你基本上要勾上「視圖渲染時間」,而不是RENDER_RESPONSE階段beforePhase。 JSF提供了幾種方法,以勾就可以了:

  1. 在一些主模板,附加preRenderView監聽器<f:view>

    <f:view ...> 
        <f:event type="preRenderView" listener="#{bean.onPreRenderView}" /> 
        ... 
    </f:view> 
    
    public void onPreRenderView(ComponentSystemEvent event) { 
        UIViewRoot view = (UIViewRoot) event.getSource(); 
        // The view is the component tree. Just modify it here accordingly. 
        // ... 
    }   
    
  2. 或者,實施PreRenderViewEvent全球SystemEventListener

    public class YourPreRenderViewListener implements SystemEventListener { 
    
        @Override 
        public boolean isListenerForSource(Object source) { 
         return source instanceof UIViewRoot; 
        } 
    
        @Override 
        public void processEvent(SystemEvent event) throws AbortProcessingException { 
         UIViewRoot view = (UIViewRoot) event.getSource(); 
         // The view is the component tree. Just modify it here accordingly. 
         // ... 
        } 
    
    } 
    

    讓它運行,在faces-config.xml如下注冊它:

    <application> 
        <system-event-listener> 
         <system-event-listener-class>com.example.YourPreRenderViewListener</system-event-listener-class> 
         <system-event-class>javax.faces.event.PreRenderViewEvent</system-event-class> 
        </system-event-listener> 
    </application> 
    
  3. 或者,其中你renderView()做的工作提供自定義ViewHandler

    public class YourViewHandler extends ViewHandlerWrapper { 
    
        private ViewHandler wrapped; 
    
        public YourViewHandler(ViewHandler wrapped) { 
         this.wrapped = wrapped; 
        } 
    
        @Override 
        public void renderView(FacesContext context, UIViewRoot view) { 
         // The view is the component tree. Just modify it here accordingly. 
         // ... 
    
         // Finally call super so JSF can do the rendering job. 
         super.renderView(context, view); 
        } 
    
        @Override 
        public ViewHandler getWrapped() { 
         return wrapped; 
        } 
    
    } 
    

    讓它運行,如下登記faces-config.xml

    <application> 
        <view-handler>com.example.YourViewHandler</view-handler> 
    </application> 
    
  4. 或者,鉤上ViewDeclarationLanguage#renderView(),但這是在邊緣一點,因爲它是不是真的intented操縱組件樹,但操作如何呈現視圖。


無關到具體的問題,這一切都不是針對具體的功能需求的解決方案爲您的問題聲明:

這是爲了添加樣式類添加到消息附加到樹中的任何UIInput組件,並刪除樣式類(如果它沒有附加任何消息)

你真的應該更好地面向客戶端解決方案,而不是操縱組件樹(最終會以JSF組件狀態!)。想象一下迭代組件的輸入情況,如<ui:repeat><h:inputText>。樹中只有一個輸入組件,而不是多個!通過UIInput#setStyleClass()操縱風格類將在每一輪迭代中呈現。

你會使用UIViewRoot#visitTree()如下最好訪問組件樹並收集無效的輸入組件的所有客戶ID(這visitTree()方法將透明地迭代成分考慮在內),

Set<String> invalidInputClientIds = new HashSet<>(); 
view.visitTree(VisitContext.createVisitContext(context, null, EnumSet.of(VisitHint.SKIP_UNRENDERED)), new VisitCallback() { 

    @Override 
    public VisitResult visit(VisitContext context, UIComponent component) { 
     if (component instanceof UIInput) { 
      UIInput input = (UIInput) component; 

      if (!input.isValid()) { 
       invalidInputClientIds.add(input.getClientId(context.getFacesContext())); 
      } 
     } 

     return VisitResult.ACCEPT; 
    } 
}); 

然後通過以後invalidInputClientIds將JSON數組轉換爲JavaScript,然後通過document.getElementById()抓取它們並更改className屬性。

for (var i = 0; i < invalidInputClientIds.length; i++) { 
    var invalidInput = document.getElementById(invalidInputClientIds[i]); 
    invalidInput.className += ' error'; 
} 

該JSF實用程序庫OmniFaces具有<o:highlight>分量正是這一點。

+0

謝謝你。我其實並沒有多年觸及JSF,但也許對其他人有幫助。 – jamiebarrow 2015-11-11 15:49:33