我有个问题。
我已经实现了一个PhaseListener,它的目的是向树中任何附加了消息的UIInput组件添加样式类,如果没有附加任何消息,则删除样式类。
PhaseListener在RENDER_RESPONSE阶段运行,并在调试时在beforePhase和afterPhase方法中执行它的工作。在调试时,我发现beforePhase不能访问完整的组件树,而afterPhase可以。但是,在afterPhase中所做的任何更改都不会被呈现。
我该怎么做呢?我希望这完全是服务器端的。
谢谢,
詹姆斯
发布于 2010-03-23 22:11:09
使用ViewHandler实现,但是效率不高。处于呈现响应阶段的PhaseListener没有访问组件树的权限。
发布于 2015-11-11 00:47:46
JSF组件树只有在视图构建时间之后才可用。在呈现完整的RENDER_RESPONSE组件树之前,JSF阶段不一定是访问它的好时机。在没有任何<f:viewAction>的初始GET请求期间,完整的组件树只在afterPhase中可用,因为它是在RENDER_RESPONSE期间构建的。在回发期间,完整的组件树在beforePhase中可用,但是,当导航到不同的视图时,它仍然会在RENDER_RESPONSE阶段更改,因此任何修改都将丢失。
要了解视图构建时间的确切含义,请转到问题What's the view build time?
你基本上想挂接到“视图渲染时间”,而不是RENDER_RESPONSE阶段的beforePhase。JSF提供了几种挂接它的方法:
preRenderView侦听器附加到<f:view>。...
public void onPreRenderView(ComponentSystemEvent event) { UIViewRoot onPreRenderView= (UIViewRoot) event.getSource();//视图为组件树只需在此处进行相应的修改即可。// ... }
PreRenderViewEvent实现全局SystemEventListener。公共类YourPreRenderViewListener实现SystemEventListener { @Override public boolean isListenerForSource(对象源){ return source instanceof UIViewRoot;} @Override public void processEvent(SystemEvent event) throws { UIViewRoot view = (UIViewRoot) event.getSource();//视图是组件树。只需在此处进行相应的修改即可。// ... }}
要使其运行,请在faces-config.xml com.example.YourPreRenderViewListener javax.faces.event.PreRenderViewEvent
ViewHandler,在其中您可以在renderView()中执行作业。公共类YourViewHandler扩展ViewHandlerWrapper {私有ViewHandler包装;公共YourViewHandler(ViewHandler包装){ this.wrapped = wrapped;} @Override public void renderView(FacesContext context,UIViewRoot view) { //视图是组件树。只需在此处进行相应的修改即可。// ... //最后调用super,这样JSF就可以执行渲染工作了。Super.renderView(上下文,视图);} @Override公共ViewHandler getWrapped() {返回包装;}}
要让它运行,请在faces-config.xml com.example.YourViewHandler
ViewDeclarationLanguage#renderView()上挂接,但这有点冒险,因为它实际上并不打算操作组件树,而是操作如何呈现视图。与具体问题无关的,这并不是您问题中所述的具体功能需求的正确解决方案:
,用于向树中附加了消息的任何UIInput组件添加样式类,如果没有附加任何消息,则删除样式类
您最好使用客户端解决方案,而不是操作组件树(这将以JSF组件状态结束!)。想象一下迭代组件(如<ui:repeat><h:inputText> )中的输入的情况。实际上,树中只有一个输入组件,而不是多个!通过UIInput#setStyleClass()操作style类将出现在每一轮迭代中。
您最好如下所示使用UIViewRoot#visitTree()访问组件树,并收集无效输入组件的所有客户端‘d(此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有一个组件,它就是这样做的。
https://stackoverflow.com/questions/2469004
复制相似问题