当前位置: 首页 > 面试题库 >

动态ajax导航与

顾嘉良
2023-03-14
问题内容

假设我想在我的应用程序中导航,并动态包含不同的facelet页面。我有一个像这样的commandLink:

<h:commandLink value="Link" action="#{navigation.goTo('someTest')}">
    <f:ajax render=":content" />
</h:commandLink>

这是我包含小面的地方:

<h:form id="content">
    <ui:include src="#{navigation.includePath}" />
</h:form>

导航类:

public class Navigation {
    private String viewName;

    public void goTo(String viewName) {
        this.viewName = viewName;
    }

    public String getIncludePath() {
        return resolvePath(viewName);
    }
}

我见过类似的例子,但这当然行不通。作为ui:include标记处理程序,包含发生在调用我的导航侦听器之前很长时间。包括旧的facelet,而不是新的facelet。到目前为止,我明白了。

现在让我们头疼的是:如何基于actionListener动态地包含facelet?我试图将facelet包含在preRender事件中,并在RENDER_RESPONSE之前包含phaseListener。两者都可以,但是在事件侦听器中,我无法包含包含其他preRender事件的facelet,并且在phaseListener中,单击包含的facelet之后,我得到的ID重复。但是,检查组件树会告诉我,根本没有重复的组件。也许这两个想法根本不好。

我需要一个解决方案,其中带有的页面ui:include或包含facelet的Java类的页面不必知道页面(包括页面)或确切路径。有人解决过这个问题吗?我该怎么做?

我正在使用JSF 2.1和Mojarra 2.1.15

重现问题所需要做的就是这个bean:

@Named
public class Some implements Serializable {
    private static final long serialVersionUID = 1L;
    private final List<String> values = new ArrayList<String>();

    public Some() {
        values.add("test");
    }

    public void setInclude(String include) {
    }
    public List<String> getValues() {
        return values;
    }
}

这在您的索引文件中:

<h:head>
    <h:outputScript library="javax.faces" name="jsf.js" />
</h:head>

<h:body>
    <h:form id="topform">
        <h:panelGroup id="container">
            <my:include src="/test.xhtml" />
        </h:panelGroup>
    </h:form>
</h:body>

而这在text.xhtml中

<ui:repeat value="#{some.values}" var="val">
    <h:commandLink value="#{val}" action="#{some.setInclude(val)}">
        <f:ajax render=":topform:container" />
    </h:commandLink>
</ui:repeat>

这足以产生如下错误:

javax.faces.FacesException: Cannot add the same component twice: topform:j_id-549384541_7e08d92c

问题答案:

对于OmniFaces,我也曾经通过在方法中创建<o:include>as
UIComponent而不是a
TagHandler进行过尝试。这样,在恢复视图阶段就可以记住正确的包含面,而包含组件树仅在渲染响应阶段发生变化,这正是我们想要实现的构造。FaceletContext#includeFacelet()encodeChildren()

这是一个基本的启动示例:

@FacesComponent("com.example.Include")
public class Include extends UIComponentBase {

    @Override
    public String getFamily() {
        return "com.example.Include";
    }

    @Override
    public boolean getRendersChildren() {
        return true;
    }

    @Override
    public void encodeChildren(FacesContext context) throws IOException {
        getChildren().clear();
        ((FaceletContext) context.getAttributes().get(FaceletContext.FACELET_CONTEXT_KEY)).includeFacelet(this, getSrc());
        super.encodeChildren(context);
    }

    public String getSrc() {
        return (String) getStateHelper().eval("src");
    }

    public void setSrc(String src) {
        getStateHelper().put("src", src);
    }

}

注册.taglib.xml如下:

<tag>
    <tag-name>include</tag-name>
    <component>
        <component-type>com.example.Include</component-type>
    </component>
    <attribute>
        <name>src</name>
        <required>true</required>
        <type>java.lang.String</type>
    </attribute>
</tag>

在以下视图中可以正常工作:

<h:outputScript name="fixViewState.js" />

<h:form>
    <ui:repeat value="#{includeBean.includes}" var="include">
        <h:commandButton value="Include #{include}" action="#{includeBean.setInclude(include)}">
            <f:ajax render=":include" />
        </h:commandButton>
    </ui:repeat>
</h:form>

<h:panelGroup id="include">
    <my:include src="#{includeBean.include}.xhtml" />
</h:panelGroup>

以及以下辅助bean:

@ManagedBean
@ViewScoped
public class IncludeBean implements Serializable {

    private List<String> includes = Arrays.asList("include1", "include2", "include3");
    private String include = includes.get(0);

    private List<String> getIncludes() {
        return includes;
    }

    public void setInclude(String include) {
        return this.include = include;
    }

    public String getInclude() { 
        return include;
    }

}

(此示例期望include
filesinclude1.xhtmlinclude2.xhtml并且include3.xhtml与主文件位于同一基本文件夹中)

fixViewState.js可以在这个回答中找到:H:的commandButton /
H:commandLink不首先点击工作,只能在第二次点击。为了修复JSF问题790,此脚本是必需的,从而在存在多个更新彼此父级的ajax表单时,视图状态会丢失。

还要注意,这种方式每个包含文件<h:form>在必要时都可以拥有自己的文件,因此您不必将其放在包含文件周围。

这种方法即使在Mojarra中也可以正常工作,即使回发请求来自include内的表单,但是在MyFaces中也很难失败,但在初始请求期间已经存在以下异常:

java.lang.NullPointerException
    at org.apache.myfaces.view.facelets.impl.FaceletCompositionContextImpl.generateUniqueId(FaceletCompositionContextImpl.java:910)
    at org.apache.myfaces.view.facelets.impl.DefaultFaceletContext.generateUniqueId(DefaultFaceletContext.java:321)
    at org.apache.myfaces.view.facelets.compiler.UIInstructionHandler.apply(UIInstructionHandler.java:87)
    at javax.faces.view.facelets.CompositeFaceletHandler.apply(CompositeFaceletHandler.java:49)
    at org.apache.myfaces.view.facelets.tag.ui.CompositionHandler.apply(CompositionHandler.java:158)
    at org.apache.myfaces.view.facelets.compiler.NamespaceHandler.apply(NamespaceHandler.java:57)
    at org.apache.myfaces.view.facelets.compiler.EncodingHandler.apply(EncodingHandler.java:48)
    at org.apache.myfaces.view.facelets.impl.DefaultFacelet.include(DefaultFacelet.java:394)
    at org.apache.myfaces.view.facelets.impl.DefaultFacelet.include(DefaultFacelet.java:448)
    at org.apache.myfaces.view.facelets.impl.DefaultFacelet.include(DefaultFacelet.java:426)
    at org.apache.myfaces.view.facelets.impl.DefaultFaceletContext.includeFacelet(DefaultFaceletContext.java:244)
    at com.example.Include.encodeChildren(Include.java:54)

MyFaces基本上在视图构建时结束时释放Facelet上下文,使其在视图渲染时不可用,从而导致NPE,因为内部状态具有多个无效属性。但是,可以在渲染期间添加单个组件而不是Facelet文件。我真的没有时间调查这是我的错还是MyFaces的错。这就是为什么它还没有出现在OmniFaces中的原因。

如果您仍在使用Mojarra,请随时使用。但是,我强烈建议在同一页面上使用所有可能的用例对它进行彻底的测试。Mojarra具有一些与状态保存有关的怪癖,这些怪癖在使用此构造时
可能会 失败。



 类似资料:
  • Dynamic Navbar is supported only in iOS Theme iOS7的好评特性之一是动态导航栏。当页面过渡时,导航栏元素会滑动渐变。 它只对穿透类型的布局有效 它应该在视图初始化时通过传递dynamicNavbar: true参数来启用 动态导航栏布局 动态导航栏和一般的导航栏是一样的,区别只在于,你可以对导航栏的组成部分(左、中、右)加入额外的类,来说明使用哪个过

  • 我试图动态添加在导航栏,但它一直给这个错误: 警告:mysqli_fetch_array()希望参数1是mysqli_结果,布尔值在第11行的C:\xampp\htdocs\includes\navigation.php中给出 我的PHP代码:

  • 本文向大家介绍WordPress动态页面菜单导航,包括了WordPress动态页面菜单导航的使用技巧和注意事项,需要的朋友参考一下 在编写了可以在Wordpress中创建给定页面的子页面列表的函数之后,我需要更强大,更自动的功能。为此,我创建了一个插件,该插件将创建一个包含动态创建的页面菜单的小部件。 该小部件可以确定当前正在显示的页面,并将爬到页面树上,直到找到根页面为止。在攀爬页面树的同时,插

  • 问题内容: 我有bootstrap v3。 我在菜单上使用时,它不会切换。我知道该如何使用并建立点击功能,但我认为该功能应包含在引导程序中?那么也许是JavaScript问题? 这是我包含的js / css / bootstrap文件的标头: 这是我的代码: 我可以正确设置吗? (在不相关的注释上,但可能相关吗?当菜单移动时,我单击菜单按钮,它将折叠。尽管再次按下并不会使其崩溃。因此,此问题与另一

  • 本文向大家介绍vue element-ui实现动态面包屑导航,包括了vue element-ui实现动态面包屑导航的使用技巧和注意事项,需要的朋友参考一下 vue element-ui动态面包屑导航,供大家参考,具体内容如下 直接上代码 一、template代码 二、script代码 三、css代码 css样式是放在一个单独的样式文件夹里面 以上就是面包屑的制作过程了。 关于vue.js组件的教程

  • 问题内容: 在Bootstrap网站上,子导航与部分匹配,并在您更改背景颜色或滚动到该部分。我想创建自己的菜单,但不包含所有背景色和所有内容,但是,我将CSS更改为相似,但是当我向下滚动或单击菜单项时,活动类不会切换。不知道我在做什么错。 HTML: CSS: 我检查了文件;jQuery,bootstrap.js和bootstrap.css均已正确链接。我是否必须添加一些其他的jQuery还是缺少