首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >在PhaseListener中修改JSF组件树

在PhaseListener中修改JSF组件树
EN

Stack Overflow用户
提问于 2010-03-18 18:28:45
回答 2查看 2.2K关注 0票数 1

我有个问题。

我已经实现了一个PhaseListener,它的目的是向树中任何附加了消息的UIInput组件添加样式类,如果没有附加任何消息,则删除样式类。

PhaseListener在RENDER_RESPONSE阶段运行,并在调试时在beforePhase和afterPhase方法中执行它的工作。在调试时,我发现beforePhase不能访问完整的组件树,而afterPhase可以。但是,在afterPhase中所做的任何更改都不会被呈现。

我该怎么做呢?我希望这完全是服务器端的。

谢谢,

詹姆斯

EN

回答 2

Stack Overflow用户

回答已采纳

发布于 2010-03-23 22:11:09

使用ViewHandler实现,但是效率不高。处于呈现响应阶段的PhaseListener没有访问组件树的权限。

票数 0
EN

Stack Overflow用户

发布于 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提供了几种挂接它的方法:

  1. 在某些主模板中,将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()方法将透明地将迭代组件考虑在内):

代码语言:javascript
复制
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属性。

代码语言:javascript
复制
for (var i = 0; i < invalidInputClientIds.length; i++) {
    var invalidInput = document.getElementById(invalidInputClientIds[i]);
    invalidInput.className += ' error';
}

JSF实用工具库OmniFaces有一个组件,它就是这样做的。

票数 2
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/2469004

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档