0

After carrying on a project of a colleague of mine I'm facing some problems with a little dialogue. I was asked to copy a component and give it a new name. But there started the problem: I was able to build the dialogue and sending the component to my backing bean (unfortunately a SessionScoped one), also the new name found its way and saving is working too BUT the save button of my dialogue shows some weird behaviour. And as the code will show I have tried a lot of variants for it (with different results, described in the comments above them).

At the end I simply want three little things: get the JSF lifecycle only called once, a working required for my inputText-field and a still usable view after successful saving.

If you need more code e.g of the composite components starting with bal or of the backing bean, just drop a note and I will take care of it.

I'm aware of the fact that fetching the data every time from the database is bad style in ui:repeat, but I haven't seen a different way with the SessionScoped-Bean I have to work with (ViewScoped would for sure be better here, but time changing it, is, like always, not there).

Here is my code, using Primefaces 5.3 and the current version of 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} &raquo; #{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>

Edit: Just some additional information concerning 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>

and 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>
Nairi
  • 68
  • 6
  • Strange bug indeed. Let's try some simple things first. What happens if you replace the BootsFaces input field by a PrimeFaces input field? Or what happens if you use a BootsFaces CommandButton instead of its PrimeFaces counterpart? (`) – Stephan Rauh Jul 01 '16 at 07:27
  • I should add that using the BootsFaces b:commandButton requires you to add a b:fetchBeanInfo component in order to populate the JavaScript variable you're using. See http://showcase.bootsfaces.net/forms/FetchBeanInfos.jsf for a detailed description. – Stephan Rauh Jul 01 '16 at 07:30
  • @Stephan Rauh Changing the input field from Bootsfaces to Primefaces changes nothing. Also changing the commandButton from PrimeFaces to Bootfaces gives the same result. I tried followig buttons: – Nairi Jul 01 '16 at 08:51
  • That makes it unlikely that the error is caused by BootsFaces or PrimeFaces. You could replace the PrimeFaces dialog by a b:modal, but I don't think that makes any difference. You could also try to replace bal:row by b:panel. The only other unusual attribute I can spot is prepend="false". This is discourages for many reasons, but I don't see how it cause your errors. BTW, did you check your browser's JavaScript console for errors? – Stephan Rauh Jul 01 '16 at 13:28
  • @Stephan Rauh Just added my composite components to my first post and also tried to remove prepentId="false", but the behaviour stays the same. The JavaScript console shows (unfortunately) no errors. Of course I can try to use b:modal, but I also think that it won't help fixing my problem. – Nairi Jul 01 '16 at 13:56
  • two remarks: [mcve] and off-topic: your namespace for the composite is not jsf-2.2 'compliant'. The others are – Kukeltje Jul 02 '16 at 21:39

0 Answers0