修改 PhaseListener 中的 JSF 组件树

2023-11-29

我有一个问题。

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

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

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

Thanks,

James


JSF 组件树仅在视图构建时间之后才可用。这RENDER_RESPONSE阶段不一定是在渲染之前访问完整的 JSF 组件树的好时机。在初始 GET 请求期间没有任何<f:viewAction>,完整的组件树仅在afterPhase因为它是在RENDER_RESPONSE。在回发期间,完整的组件树在beforePhase但是,当导航到不同的视图时,它仍然会改变during the RENDER_RESPONSE阶段,因此任何修改都会丢失。

要了解视图构建时间到底是多少,请转到问题视图构建时间是多少?

您基本上想要挂钩“查看渲染时间”而不是beforePhase of RENDER_RESPONSE阶段。 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. 或者,实施一个全球性的SystemEventListener for 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.
            // ...
        }
    
    }
    

    要让它运行,请按如下所示注册它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. 或者,提供自定义ViewHandler你在哪里工作renderView().

    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(),但这有点边缘,因为它并不是真正旨在操纵组件树,而是操纵如何渲染视图。


无关对于具体问题,这一切都不是您问题中所述的具体功能要求的正确解决方案:

这意味着将样式类添加到树中附加有消息的任何 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类似于 JavaScript 的 JSON 数组,然后通过 JavaScript 获取它们document.getElementById()并改变className属性。

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

JSF 实用程序库OmniFaces has a <o:highlight>正是执行此操作的组件。

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

修改 PhaseListener 中的 JSF 组件树 的相关文章

随机推荐

  • 等待unity3d中的动画完成

    我有一个动画在Update 函数 在Switch case 动画完成后 布尔值将被设置为 true My code case play animation Play play gobool true startbool false brea
  • android volley 发布二进制正文

    场景 在帖子正文中上传二进制数据 处理包含 JSON 的响应正文 如何使用 Volley 执行以下操作 curl X POST H X Application Id 3KxPB H X REST API Key jkuI9 H Conten
  • 在 React-Router 中使用 Link 传递 props

    你好 我正在尝试将 Props 传递给Details带有 React Router 的 Link 组件的组件 我不想显示Detail页面上的组件 它应该在单击按钮时呈现 但当新组件呈现时 url 也应该类似于 details KvhNJec
  • 用于非游戏相关 3D 图形编程的托管 Direct3D 或 XNA?

    哪种是进行 NET 3D 图形编程的首选方法 Direct3D 或 XNA 似乎是当前的技术 但哪一种最适合非游戏相关的编程 另外 Managed Direct 3D 是否已经停止 XNA 似乎并不真正适合非游戏开发 是的 可惜 MS 停止
  • Windows 7 任务栏中的 Delphi 窗体图标模糊

    I have an application having 2 Forms each Form and Application have individual Icon On Form1BitBtn1 Click Form2 is Shown
  • 如何在 webview2 中检测鼠标点击 (c#/vb.net)

    我尝试获取 html 元素的单击事件 我使用的网络浏览器 instance Nothing instance WebBrowser1 Document AddHandler instance Click AddressOf Document
  • 在代码隐藏中绑定动态创建的控件

    我动态创建了在运行时在 C 代码后面创建的弹出窗口 其中填充了 xaml 中的内容 并且很难在后面的代码中绑定它们 现在 当它被创建时 它会循环遍历 xaml 中的项目并为每个项目创建一个关联的复选框 ListView listView n
  • 是什么使

    周围似乎有某种魔力
  • 无法获取移动服务的位置信息 - 错误 400

    我尝试按照 Scotts 在此页面上对 Azure 的介绍进行操作 https www windowsazure com en us develop mobile tutorials get started 但在第 4 点 当我打算创建新的
  • Mysql 查询 - 使用 join/union 等

    我的数据库中有 4 个表 名为顾客 保存他们的个人详细信息以及他们在哪个项目中的哪个房间 payments 持有该项目的付款详细信息 projects 持有项目详细信息 和staff 持有员工登录信息 我还有 3 个页面 我从所有这些页面中
  • mysql命名约定

    我通常总是使用某种Hungarian Notation对于我的表中的字段名称 例如 Table Users u id u name u email etc Posts p id p u id p title p content etc 但最
  • Node.js Express:对 ejs 模板感到困惑

    我把我的ejs模板文件在views文件夹如 views foo html layout html 所以我配置我的 ejs 模板 app set views dirname views app engine html require ejs
  • 施工期间的虚拟功能解决方法

    我有一个具有虚函数的基类 我想在构造过程中调用该类 因为我希望为每个派生类调用该函数 我知道我无法在构造过程中调用虚拟函数 但我想不出一个优雅的 即避免重复代码 解决方案 在构造过程中调用虚函数有哪些解决方法 我想避免这种情况的原因是因为我
  • 如何在 html 页面中创建“转到邮箱”链接?

    我正在创建一个确认页面 其中显示 验证电子邮件已发送到您的邮箱 电子邮件受保护 请点击
  • 如何将 Gradle 插件(及其依赖项)加载到 build.gradle 中?

    我有一个有两个 gradle 文件的项目 build gradle and myPlugin gradle The myPlugin gradle实现了插件接口 该插件还依赖于osDetector gradle 插件 我将两个 gradle
  • open() 函数对于包含特殊字符的文件路径无法正确运行

    我正在写这个简单的代码 file input File to read fhand open file r 我要打开的文件名为 test txt 它位于子文件夹中 因此 我在请求的输入中输入的是 DB test txt 嗯 它不起作用 返回
  • 如何在php中的特定日期发送?

    我想要一张电子贺卡或类似的东西 用户可以选择电子贺卡 选择后 他必须输入一些字段 例如姓名 收件人和发件人 电子邮件 收件人和发件人 消息 我想让用户选择发送电子贺卡的日期 如何在特定日期发送电子贺卡 我需要编写一个每天运行的脚本吗 怎么做
  • 带有角度的 requirejs - 不解决嵌套路由的控制器依赖关系

    The RequireJS当路由具有多个级别时 无法正确解决依赖关系 如下所示http www example com profile view 如果我有http www example com view 控制器依赖性已正确解决 我的 bo
  • python:递归检查以确定字符串是否是回文

    我的任务是定义一个过程 is palindrome 它将字符串作为输入 并返回一个布尔值 指示输入字符串是否是回文 在这种情况下 单个字母应该返回 True 空字符串也应该返回 True 不幸的是 我没有得到预期的结果 我很感激你的帮助 我
  • 修改 PhaseListener 中的 JSF 组件树

    我有一个问题 我已经实现了一个 PhaseListener 它的目的是向树中附加有消息的任何 UIInput 组件添加一个样式类 如果没有附加任何消息 则删除该样式类 PhaseListener 在 RENDER RESPONSE 阶段运行