Warning: file_get_contents(/data/phpspider/zhask/data//catemap/9/three.js/2.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
JSF:如何避免';已在视图中找到组件ID;复合元件双插入错误_Jsf_Jsf 2.3 - Fatal编程技术网

JSF:如何避免';已在视图中找到组件ID;复合元件双插入错误

JSF:如何避免';已在视图中找到组件ID;复合元件双插入错误,jsf,jsf-2.3,Jsf,Jsf 2.3,我知道是什么导致了以下问题。我正在寻找一种优雅的方法来解决这个问题,而不是我找到的一种蛮力(非干性)解决方法 我在一个模板中有一个高度可重用的h:form(我意识到“god forms”的危险,这不是一个很好的god forms),我通过模板将可编辑的内容插入到该表单中,在页面的顶部和底部都有一个相同的命令按钮操作栏。(此模板有数百个客户端,有些客户端在模板中插入不同的操作栏。) 我这样做的唯一原因(顶部和底部)是用户方便;我发现,在使用许多内容管理系统时,必须向下或向上滚动才能在长表单上找到保

我知道是什么导致了以下问题。我正在寻找一种优雅的方法来解决这个问题,而不是我找到的一种蛮力(非干性)解决方法

我在一个模板中有一个高度可重用的
h:form
(我意识到“god forms”的危险,这不是一个很好的god forms),我通过模板将可编辑的内容插入到该表单中,在页面的顶部和底部都有一个相同的命令按钮操作栏。(此模板有数百个客户端,有些客户端在模板中插入不同的操作栏。)

我这样做的唯一原因(顶部和底部)是用户方便;我发现,在使用许多内容管理系统时,必须向下或向上滚动才能在长表单上找到保存按钮(或操作栏中的其他按钮),这很烦人

模板(请不要告诉我它是“上帝形式”)有:

注意上面我是如何给CC`util:edit_actions'一个id的(我直到最近才在这个CC上做这个,原因我将在下面解释)

因此,您可以看到,完全相同的操作工具栏被插入到页面的表单部分的顶部和底部。但是,如果您使用传递给
edit\u actions
的id如上所示执行此操作,则会得到:

javax.servlet.ServletException: Component ID edit_actions has already been found in the view.  
多年来,我一直在成功地使用这个模板,直到我引入了显式id,原因如下所示

edit_actions
CC有一些命令按钮,例如:

 <composite:implementation>
  <p:toolbar>
   <p:toolbarGroup>
    <p:commandButton 
      ajax ="true"
      action="#{cc.attrs.manager.crud.update}"
      value="Save" 
      update="@form"
      id="save"
     />
         ...
每当在数百个使用它的edit.xhtml客户端页面中执行插入操作时,我必须为插入的
edit\u操作
CC提供一个显式id:

<ui:composition template="/template.xhtml">
...
    <ui:define name="actions">
        <util:edit_actions id="edit_actions" manager="#{manager}"/>
    </ui:define>

注意,上面的代码不是代码,我认为这是最重要的编码实践之一,而JSF通常在寻址方面特别好。确保上述模板插入模式和id模式在成百上千的

edit.xhtml
页面中得到了解决,这很容易出错,除非我能够以某种方式封装
ui:define
对,同时仍然能够注入任何兼容的
{manager}

然后,条件要求测试必须在上部和下部保存按钮上进行测试:

<p:inputText 
  id="newLinkUrl"
  value="#{cc.attrs.manager.newLinkUrl}"
  required="#{param['edit_actions_upper:save']==null and param['edit_actions_lower:save']==null}"
  validator="urlValidator"
 />
通过
edit.xhtml
尝试使用:

<ui:composition 
    xmlns="http://www.w3.org/1999/xhtml"
    xmlns:f="http://xmlns.jcp.org/jsf/core"
    xmlns:ui="http://xmlns.jcp.org/jsf/facelets"
    xmlns:util="http://xmlns.jcp.org/jsf/composite/util">

    <ui:define name="actions_upper">
        <util:edit_actions id="edit_actions_upper" manager="#{manager}"/>
    </ui:define>

    <ui:define name="actions_lower">
        <util:edit_actions id="edit_actions_lower" manager="#{manager}"/>
    </ui:define>

</ui:composition>
<ui:composition template="/template.xhtml">

    <ui:include src="/include/edit_actions_defines.xhtml">
        <ui:param name="manager" value="#{specificManager}"/>            
    </ui:include>

似乎被默默地忽略了。

我已经找到了一个解决方案(真正的解决办法)来解决我自己的问题,满足我的要求。不漂亮,但可能对其他人有用

我没有测试特定的组件id,而是使用regexp:

/**
 * Searches for a component id ending in ":save".
 * 
 * @return 
 */
public boolean isSaveButtonPressed() {        
    Map<String, String> parameterMap = FacesContext.getCurrentInstance()
            .getExternalContext().getRequestParameterMap();
    for (String key : parameterMap.keySet()) {
        boolean matches = Pattern.matches("^j.*:save",key);
        if (matches) return true;
    }
    return false;
}
/**
*搜索以“:save”结尾的组件id。
* 
*@返回
*/
公共布尔值isSaveButtonPressed(){
映射参数Map=FacesContext.getCurrentInstance()
.getExternalContext().getRequestParameterMap();
for(字符串键:parameterMap.keySet()){
布尔匹配=模式匹配(^j.*:save),键);
如果(匹配)返回true;
}
返回false;
}
所需的测试很简单:

<p:inputText 
  id="newLinkUrl"
  value="#{cc.attrs.manager.newLinkUrl}"
  required="#{not cc.attrs.manager.saveButtonPressed}"
  validator="urlValidator"
/>

然后,当插入我的
util:edit_actions
组件(为了方便用户,它将通过模板显示表单的顶部和底部)时,我没有向它传递显式id,我只是让JSF生成它们,它们对于两个保存按钮都是不同的(不再冲突)


所以我可以让我的两次注射
edit_actions
cake并吃掉它。URL字符串字段上的
required
测试按照两个保存按钮的要求正确失败。

您是否考虑过使用
composite:insertChildren
并将所有编辑组件嵌套在包含上下按钮的组合中?欢迎所有建议,但我看不出
composite:insertChildren
有什么帮助。我已经使用它将特定于编辑特定实体类型的方面(以及匹配的支持bean
manager
)注入到编辑CCs中,这些CCs包括在问题中描述的系统中(尽管没有显示),并且已经在上下按钮之间。上面和下面的按钮总是相同的(对于给定的页面),但是我将不同的按钮集(以及它们匹配的
manager
)放入同一个模板中,用于不同的实体类型(通过
edit.xhtml
)。我指的是重构页面,以便表单组件可以嵌套在包含上下按钮的CC中,但如果要在其中插入子项,则可能不适合您。我想您可能已经想到了这一点,但是如果您不需要支持小型设备(电话),我已经使用了一个固定的div来按住临时按钮(save等),以实现您对长多页表单的需求。
<p:inputText 
  id="newLinkUrl"
  value="#{cc.attrs.manager.newLinkUrl}"
  required="#{param['edit_actions_upper:save']==null and param['edit_actions_lower:save']==null}"
  validator="urlValidator"
 />
<ui:composition 
    xmlns="http://www.w3.org/1999/xhtml"
    xmlns:f="http://xmlns.jcp.org/jsf/core"
    xmlns:ui="http://xmlns.jcp.org/jsf/facelets"
    xmlns:util="http://xmlns.jcp.org/jsf/composite/util">

    <ui:define name="actions_upper">
        <util:edit_actions id="edit_actions_upper" manager="#{manager}"/>
    </ui:define>

    <ui:define name="actions_lower">
        <util:edit_actions id="edit_actions_lower" manager="#{manager}"/>
    </ui:define>

</ui:composition>
<ui:composition template="/template.xhtml">

    <ui:include src="/include/edit_actions_defines.xhtml">
        <ui:param name="manager" value="#{specificManager}"/>            
    </ui:include>
/**
 * Searches for a component id ending in ":save".
 * 
 * @return 
 */
public boolean isSaveButtonPressed() {        
    Map<String, String> parameterMap = FacesContext.getCurrentInstance()
            .getExternalContext().getRequestParameterMap();
    for (String key : parameterMap.keySet()) {
        boolean matches = Pattern.matches("^j.*:save",key);
        if (matches) return true;
    }
    return false;
}
<p:inputText 
  id="newLinkUrl"
  value="#{cc.attrs.manager.newLinkUrl}"
  required="#{not cc.attrs.manager.saveButtonPressed}"
  validator="urlValidator"
/>