Modification JSF arborescence des composants dans PhaseListener
Question
Je vais avoir un problème.
Je l'ai mis en place un PhaseListener, qui vise à ajouter une classe de style à tous les composants UIInput dans l'arborescence qui ont des messages qui leur sont rattachés, et supprime la classe de style si elle n'a pas de messages qui leur sont rattachés.
Le PhaseListener court dans la phase RENDER_RESPONSE, et ne c'est le travail dans les deux méthodes beforePhase et afterPhase pendant le débogage. Bien que le débogage, je trouve que beforePhase n'a pas accès à l'arbre complet du composant, mais afterPhase fait. Toute modification apportée à afterPhase ne sont pas rendus bien.
Comment puis-je cela? Je veux que ce soit complètement côté serveur.
Merci,
James
La solution 2
Mis en œuvre en utilisant un ViewHandler, mais il est pas efficace. PhaseListener en rendu la phase de réponse n'a pas accès à l'arborescence des composants.
Autres conseils
L'arborescence des composants JSF est disponible après le moment de la construction de la vue. La phase RENDER_RESPONSE
est pas nécessairement un bon moment pour avoir accès à l'arbre complet des composants JSF avant qu'il ne soit rendu. Au cours d'une première demande GET sans <f:viewAction>
, l'arbre complet du composant est disponible uniquement dans le afterPhase
comme il est en cours de construction au cours de la RENDER_RESPONSE
. Au cours d'un postback l'arbre complet du composant est disponible dans beforePhase
, cependant, quand une navigation à une autre vue a eu lieu, il serait Stil changer pendant la phase de RENDER_RESPONSE
, de sorte que toute modification me perdrais .
Pour en savoir exactement ce que le temps de construction de vue est, la tête à la question Quel est le temps de construction de vue
Vous voulez essentiellement à accrocher « vue de rendre le temps » plutôt que beforePhase
de phase RENDER_RESPONSE
. JSF offre plusieurs façons de crochet sur elle:
-
Dans certains modèle maître, attacher un écouteur d'
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. // ... }
-
Ou, mettre en œuvre un
SystemEventListener
PreRenderViewEvent
.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. // ... } }
Pour le faire fonctionner, inscrivez-vous comme ci-dessous
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>
-
Ou, fournir une coutume
ViewHandler
dans laquelle vous faites le travail dansrenderView()
.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; } }
Pour le faire fonctionner, inscrivez-vous ci-dessous dans
faces-config.xml
:<application> <view-handler>com.example.YourViewHandler</view-handler> </application>
-
Ou, crochet sur OmniFaces a a
<o:highlight>
composante qui fait exactement cela.