在进行了我的一位同事的项目后,我在进行一些对话时遇到了一些问题。我被要求复制一个组件并给它一个新名称。但是问题开始了:我能够构建对话并将组件发送到我的支持 bean(不幸的是一个 SessionScoped 的),新名称也找到了它的方式并且保存也在工作但是我的对话的保存按钮显示了一些奇怪行为。正如代码将显示的那样,我已经尝试了很多变体(不同的结果,在它们上面的评论中描述)。
最后,我只想要三件小事:只调用一次 JSF 生命周期、我的 inputText-field 所需的工作以及成功保存后仍然可用的视图。
如果您需要更多代码,例如以 bal 或 backing bean 开头的复合组件的代码,只需写一个注释,我会处理它。
我知道每次从数据库中获取数据在 ui:repeat 中都是不好的风格,但是我没有看到我必须使用的 SessionScoped-Bean 的不同方式(ViewScoped 肯定会更好在这里,但时间改变它,像往常一样,不在那里)。
这是我的代码,使用 Primefaces 5.3 和当前版本的 Bootsfaces:
<html
xmlns="http://www.w3.org/1999/xhtml"
xmlns:h="http://xmlns.jcp.org/jsf/html"
xmlns:ui="http://xmlns.jcp.org/jsf/facelets"
xmlns:f="http://xmlns.jcp.org/jsf/core"
xmlns:p="http://primefaces.org/ui"
xmlns:b="http://bootsfaces.net/ui"
xmlns:bal="http://java.sun.com/jsf/composite/bal/components">
<ui:composition template="/template/main.xhtml">
<ui:define name="content">
<bal:pageHeading title="#{msg.menu_settings} » #{msg.menu_components}">
<h:form>
<div class="btn-group pull-right">
<b:commandButton look="link" styleClass="as-link" size="lg" action="#{componentController.createCategory()}" value="#{msg.create_category}" title="#{msg.create_category}" iconAwesome="plus-circle" />
</div>
</h:form>
</bal:pageHeading>
<bal:row id="panelRow">
<h:form id="masterForm">
<ui:repeat value="#{componentController.getComponentcategoryListByCompany(loginController.company)}" var="componentcategory">
<bal:panel title="#{componentcategory.name}" description="#{componentcategory.description}" expanded="false" id="categoryForm">
<f:facet name="tools">
<b:commandButton look="link" styleClass="as-link" action="#{componentController.createComponent(componentcategory)}" value="#{msg.create_component}" title="#{msg.create_component}" size="md" iconAwesome="plus-circle" immediate="true" />
</f:facet>
<ul class="list-unstyled">
<ui:repeat value="#{componentcategory.componentList}" var="componentItem">
<li class="list-group-item">
<div class="row">
<div class="col-sm-7 name-col">#{componentItem.name}</div>
<div class="col-sm-5 text-right">
<b:buttonGroup>
<p:commandButton styleClass="btn btn-link as-link" style="float: left;" value="#{msg.copy_component}" title="#{msg.copy_component}" icon="fa fa-files-o" >
<p:ajax listener="#{componentController.sendComponentToCopy(componentItem)}" oncomplete="PF('copyComponentDialog').show()" process="panelRow:masterForm" partialSubmit="true" />
</p:commandButton>
</b:buttonGroup>
</div>
</div>
</li>
</ui:repeat>
<ui:fragment rendered="#{empty componentcategory.componentList}">
<li class="list-group-item list-group-item-info">#{msg.no_components_available}</li>
</ui:fragment>
</ul>
</bal:panel>
</ui:repeat>
<ui:fragment rendered="#{empty componentController.getComponentcategoryListByCompany(loginController.company)}">
<ul class="list-unstyled">
<li class="list-group-item list-group-item-info">#{msg.no_categories_available}</li>
</ul>
</ui:fragment>
</h:form>
</bal:row>
<p:dialog id="dlg" widgetVar="copyComponentDialog" resizable="false" draggable="false" showEffect="fade" hideEffect="fade" modal="true">
<h:form id="dlgForm" prependId="false">
<bal:panel id="copy_component_view" title="#{msg.copy_component}" styleClass="form-panel" collapsible="false">
<b:message for="name" showSummary="false"/>
<b:inputText value="#{componentController.copiedComponentName}" id="name" label="#{msg.name}" fieldSize="sm" required="true" requiredMessage="#{msg.name_required}" />
<bal:panel id="buttons">
<bal:row id="row" colStyleClass="btn-group">
<ui:remove>
<!-- Required works - After saving panels are no longer toggleable - JSF-lifecycle called twice -->
<p:commandButton value="#{msg.save}" styleClass="btn btn-primary" icon="fa fa-check">
<p:ajax listener="#{componentController.copyComponent()}" partialSubmit="true" process="copy_component_view" update="copy_component_view :panelRow:masterForm" oncomplete="if(!args.validationFailed) PF('copyComponentDialog').hide()" />
</p:commandButton>
<!-- Required doesn't work - After saving panels are toggleable, but view not updated - JSF-lifecycle called twice -->
<p:commandButton value="#{msg.save}" styleClass="btn btn-primary" icon="fa fa-check" ajax="false">
<p:ajax listener="#{componentController.copyComponent()}" partialSubmit="true" process="copy_component_view" update="copy_component_view :panelRow:masterForm" oncomplete="if(!args.validationFailed) PF('copyComponentDialog').hide()" />
</p:commandButton>
<!-- Required works - After saving panels are no longer toggleable - JSF-lifecycle called twice -->
<p:commandButton value="#{msg.save}" styleClass="btn btn-primary" icon="fa fa-check" actionListener="#{componentController.copyComponent()}" partialSubmit="true" process="copy_component_view" update="copy_component_view :panelRow:masterForm" oncomplete="if(!args.validationFailed) PF('copyComponentDialog').hide()" />
<!-- Required works - After saving panels are no longer toggleable - JSF-lifecycle called once -->
<p:commandButton value="#{msg.save}" styleClass="btn btn-primary" icon="fa fa-check" action="#{componentController.copyComponent()}" partialSubmit="true" process="copy_component_view" update="copy_component_view :panelRow:masterForm" oncomplete="if(!args.validationFailed) PF('copyComponentDialog').hide()" />
<!-- Required doesn't work - After saving panels are toggleable, view updated - JSF-lifecycle called once -->
<p:commandButton value="#{msg.save}" styleClass="btn btn-primary" icon="fa fa-check" ajax="false" action="#{componentController.copyComponent()}" partialSubmit="true" process="copy_component_view" update="copy_component_view :panelRow:masterForm" oncomplete="if(!args.validationFailed) PF('copyComponentDialog').hide()" />
<!-- Required works - After saving panels are no longer toggleable - JSF-lifecycle called once -->
<p:commandButton value="#{msg.save}" styleClass="btn btn-primary" icon="fa fa-check" partialSubmit="true" process="copy_component_view" update="copy_component_view :panelRow:masterForm" oncomplete="if(!args.validationFailed) PF('copyComponentDialog').hide()">
<f:actionListener binding="#{componentController.copyComponent()}" />
</p:commandButton>
<!-- Required doesn't work - After saving panels are toggleable, view updated - JSF-lifecycle called once -->
<p:commandButton value="#{msg.save}" styleClass="btn btn-primary" icon="fa fa-check" ajax="false" partialSubmit="true" process="copy_component_view" update="copy_component_view :panelRow:masterForm" oncomplete="if(!args.validationFailed) PF('copyComponentDialog').hide()">
<f:actionListener binding="#{componentController.copyComponent()}" />
</p:commandButton>
<!-- Required works - After saving panels are no longer toggleable - JSF-lifecycle called once -->
<p:commandButton value="#{msg.save}" styleClass="btn btn-primary" icon="fa fa-check" partialSubmit="true" process="copy_component_view" update="copy_component_view :panelRow:masterForm" oncomplete="if(!args.validationFailed) PF('copyComponentDialog').hide()">
<f:actionListener binding="#{componentController.copyComponent()}" />
</p:commandButton>
</ui:remove>
<!-- Required doesn't work- After saving panels are toggleable, view updated - JSF-lifecycle called once -->
<p:commandButton value="#{msg.save}" styleClass="btn btn-primary" icon="fa fa-check" ajax="false" actionListener="#{componentController.copyComponent()}" partialSubmit="true" process="copy_component_view" update="copy_component_view :panelRow:masterForm" oncomplete="if(!args.validationFailed) PF('copyComponentDialog').hide()" />
<b:commandButton value="#{msg.cancel}" iconAwesome="close" look="default" immediate="true" onclick="PF('copyComponentDialog').hide()" />
</bal:row>
</bal:panel>
</bal:panel>
</h:form>
</p:dialog>
</ui:define>
</ui:composition>
</html>
编辑: 只是一些关于 bal:panel 的附加信息:
<?xml version='1.0' encoding='UTF-8' ?>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml"
xmlns:cc="http://xmlns.jcp.org/jsf/composite"
xmlns:ui="http://xmlns.jcp.org/jsf/facelets"
xmlns:h="http://xmlns.jcp.org/jsf/html"
xmlns:c="http://xmlns.jcp.org/jsp/jstl/core">
<!-- INTERFACE -->
<cc:interface>
<cc:attribute name="title" type="java.lang.String" />
<cc:attribute name="description" type="java.lang.String" />
<cc:attribute name="subtitle" type="java.lang.String" />
<cc:attribute name="subtitle" type="java.lang.String" />
<cc:attribute name="leftFooter" type="java.lang.String"/>
<cc:attribute name="rightFooter" type="java.lang.String" />
<cc:attribute name="closable" type="java.lang.Boolean" default="false" />
<cc:attribute name="collapsible" type="java.lang.Boolean" default="true" />
<cc:attribute name="expanded" type="java.lang.Boolean" default="true" />
<cc:attribute name="styleClass" type="java.lang.String" />
<cc:attribute name="style" type="java.lang.String" />
<cc:attribute name="titleStyle" type="java.lang.String" />
<cc:attribute name="labelValue" />
<cc:attribute name="labelLook" default="plain"/>
<cc:attribute name="labelStyleClass" />
<cc:attribute name="labelStyle" />
<cc:facet name="tools" />
</cc:interface>
<!-- IMPLEMENTATION -->
<cc:implementation>
<div id="#{cc.clientId}" class="ibox float-e-margins #{!cc.attrs.expanded?'border-bottom':''} #{cc.attrs.styleClass}" style="#{cc.attrs.style?cc.attrs.style:''}">
<ui:fragment rendered="#{not empty cc.attrs.title}">
<div class="ibox-title" style="#{not empty cc.attrs.titleStyle?cc.attrs.titleStyle:''}">
<span class="name-col">
<span>
<h5>#{cc.attrs.title}
<ui:fragment rendered="#{not empty cc.attrs.subtitle}">
<small class="m-l-sm">#{cc.attrs.subtitle}</small>
</ui:fragment>
<ui:fragment rendered="#{not empty cc.attrs.description}">
<h:outputLink value="" styleClass="ui-commandlink ui-widget btn-md">
<i class="fa fa-info-circle" data-toggle="tooltip" data-placement="auto" data-original-title="#{cc.attrs.description}" />
</h:outputLink>
</ui:fragment>
</h5>
<ui:fragment rendered="#{not empty cc.attrs.labelValue}">
<span class="label label-#{cc.attrs.labelLook} #{cc.attrs.labelStyleClass}" style="#{cc.attrs.labelStyle}">#{cc.attrs.labelValue}</span>
</ui:fragment>
</span>
</span>
<div class="ibox-tools">
<cc:renderFacet name="tools" />
<ui:fragment rendered="#{cc.attrs.collapsible eq true}">
<a class="collapse-link">
<i class="#{!cc.attrs.expanded?'fa fa-chevron-down':'fa fa-chevron-up'}"></i>
</a>
</ui:fragment>
<ui:fragment rendered="#{cc.attrs.closable eq true}">
<a class="close-link">
<i class="fa fa-times"></i>
</a>
</ui:fragment>
</div>
</div>
</ui:fragment>
<c:if test="#{cc.childCount gt 0}">
<div class="ibox-content" style="display: #{!cc.attrs.expanded and cc.attrs.collapsible?'none':'block'};">
<cc:insertChildren />
</div>
</c:if>
<ui:fragment rendered="#{not empty cc.attrs.leftFooter or not empty cc.attrs.rightFooter}">
<div class="ibox-footer">
<ui:fragment rendered="#{not empty cc.attrs.rightFooter}">
<span class="pull-right">
#{cc.attrs.rightFooter}
</span>
</ui:fragment>
<ui:fragment rendered="#{not empty cc.attrs.leftFooter}">
#{cc.attrs.leftFooter}
</ui:fragment>
</div>
</ui:fragment>
</div>
</cc:implementation>
</html>
和 bal:row:
<?xml version='1.0' encoding='UTF-8' ?>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml"
xmlns:cc="http://xmlns.jcp.org/jsf/composite">
<!-- INTERFACE -->
<cc:interface>
<cc:attribute name="colStyleClass" type="java.lang.String" />
<cc:attribute name="rowStyleClass" type="java.lang.String" />
</cc:interface>
<!-- IMPLEMENTATION -->
<cc:implementation>
<div id="#{cc.clientId}" class="row #{cc.attrs.rowStyleClass}" >
<div class="col-lg-12 #{cc.attrs.colStyleClass}">
<cc:insertChildren />
</div>
</div>
</cc:implementation>
</html>