pass method through ui:include to custom component - jsf-2

I have 3 files:
main.xhtml
<ui:include src="included.xhtml">
<ui:param name="bean" value="#{invoices}" />
<ui:param name="method" value="initExchange" />
</ui:include>
included.xhtml
<s:compositeComponent bean="#{bean}" beanMethod="#{method}"
buttonActionListener="#{bean[method]()}" />
compositeComponent.xhtml
<cc:interface>
<cc:attribute name="bean" />
<cc:attribute name="beanMethod" />
<cc:attribute name="buttonActionListener" method-signature="void f()" />
</cc:interface>
<cc:implementation>
<h:outputText value="#{cc.attrs.bean}" />
<h:outputText value="#{cc.attrs.beanMethod}" />
<p:commandButton actionListener="#{cc.attrs.buttonActionListener}" />
h:outputTexts are OK. But clicking on button gives exception:
Target Unreachable, identifier 'bean' resolved to null
How to pass the method to button's actionListener?

It works when actionListener in composite component is written as bean[method] like in included.xhtml:
<p:commandButton actionListener="#{cc.attrs.bean[cc.attrs.beanMethod]}" />
So generally passing method attributes through multiple stages should always be done by separate bean and method rather then one attribute with 'method-signature'.

Related

JSF: Update and add new request params

I have a page with the following params:
<f:metadata>
<f:event type="preRenderView" listener="#{busquedaBean.init}" />
<f:viewParam name="k" value="#{busquedaBean.keyword}" />
<f:viewParam name="categoryId" value="#{busquedaBean.categoryId}" />
<f:viewParam name="minprice" value="#{busquedaBean.minPrice}" />
<f:viewParam name="maxprice" value="#{busquedaBean.maxPrice}" />
</f:metadata>
All of them are optional. I need to do 2 things, which I wasn't able to do so far:
1) Add new params (keeping the previous params). This is what I tried for adding price params:
<h:outputText value="Precio diario" />
<o:form includeRequestParams="true">
<h:outputText value="min: " />
<p:inputText id="min" value="#{busquedaBean.minPrice}" />
<h:outputText value="max: " />
<p:inputText id="max" value="#{busquedaBean.maxPrice}" />
<p:commandButton icon="ui-icon-search" ajax="false">
<f:param name="minprice" value="#{busquedaBean.minPrice}" />
<f:param name="maxprice" value="#{busquedaBean.maxPrice}" />
</p:commandButton>
</o:form>
This basically works but the problem is that the URL is not updated. if the params in the URL were ?minprice=10&maxprice=200 and I update those values, the url remains the same. if these params were not included in the url, they won't be added and the filter won't work.
2) Updating the value of a param:
When categoryId is not empty, I want to show a button that will clear this param. This is what I tried:
<p:button outcome="/busqueda" includeViewParams="true" >
<f:param name="categoryId=" value="" />
</p:button>
But this button makes a GET to this URL: /busqueda/?categoryId=%3D&categoryId=1
The categoryId param appears twice. How can I just update the existing param?
I'm using MyFaces 2.1.14, Tomcat 7, Primefaces 4.0, Omnifaces
Thanks!
I was looking at this in the wrong way. includeViewParams=true will make the request include all the params declared in f:metadata with the current values. if such value is null, then the parameter is not included.
So.. to add price params:
<h:form >
<h:outputText value="$ " />
<p:inputText id="min" value="#{busquedaBean.minPrice}"/>
<h:outputText value=" a $ " />
<p:inputText id="max" value="#{busquedaBean.maxPrice}"/>
<p:commandButton icon="ui-icon-search" ajax="false" action="/busqueda?faces-redirect=true&includeViewParams=true" />
</h:form>
And to remove a param:
<p:commandButton action="#{busquedaBean.removeCategory}" ajax="false" icon="ui-icon-close" />
In the backing bean:
public String removeCategory() {
categoryId = null;
return "/busqueda?faces-redirect=true&includeViewParams=true";
}

Show dialog when the input data is validated <p:confirmDialog> [duplicate]

This question already has an answer here:
How to display dialog only on complete of a successful form submit
(1 answer)
Closed 6 years ago.
For my school project I have to realize a mini website where I use primefaces framework. In a form I want after pressing the Save button two things:
1 - Validate the data entered. that's why I put
<p:message for="date" /> and <p:message for="zone" />
As the values ​​are not correct, the dialog box should not be displayed.
2 - When all data is correct, and I click Save, I want to display my dialog box.
Now I can not. Can you help me? I use version 4 primefaces.
<h:form>
<p:panel id="panel" header="Create" style="margin-bottom:10px;border-color:blueviolet" >
<p:messages id="messages" />
<h:panelGrid columns="3">
<h:outputLabel for="date" value="Date : *" />
<p:calendar locale="fr" id="date" value="#{newBusinessCtrl.exercice.debut}" required="true" label="date" showButtonPanel="true"/>
<p:message for="date" />
<h:outputLabel for="zone" value="Zone Monétaire: *" />
<p:selectOneMenu id="zone" value="#{newBusinessCtrl.exercice.zoneChoice}" >
<f:selectItem itemLabel="Choice " itemValue="" />
<f:selectItems value="#{newBusinessCtrl.exercice.zones}" var="azone"
itemLabel="#{azone}" itemValue="#{azone}" >
</f:selectItems>
<p:message for="zone" />
</p:selectOneMenu>
<p:message for="zone" />
</h:panelGrid>
</p:panel>
<p:commandButton update="panel" value="Save" icon="ui-icon-check" style="color:blueviolet" onclick="choice.show()"/>
<p:confirmDialog message="Would you like to create accounts automatically ?"
header="Account creation" severity="alert"
widgetVar="choice" appendTo="#(body)">
<p:button outcome="personalizeAccount" value="Personalize" icon="ui-icon-star" />
<p:button outcome="autoAccount" value="Continue" icon="ui-icon-star" />
</p:confirmDialog>
Just show the dialog in Backing Bean like this:
Page:
<p:commandButton update="panel" value="Save"
icon="ui-icon-check"
style="color:blueviolet"
action="#{newBusinessCtrl.showDlg('choice')}"/>
Backing Bean:
public void showDlg(String dlgName){
RequestContext.getCurrentInstance().execute(dlgName+".show()");
}
Once the validation failed, the action won't execute and thus the dialog will not show.
If validation hasn't failed. PrimeFaces puts a global args object in the JavaScript scope which in turn has a boolean validationFailed property. You can check it before showing the dialog So you can use it this way:
<p:commandButton value="save" oncomplete="if (args && !args.validationFailed) saveDialog.show()"/>

Unable to use p:overlaypanel inside composite component

Am trying to create a composite component that will display the values as overlaypanel. But it returns the below error;
Cannot find component 'j_idt58:reviewDataTable:0:overrideCol' in view
overrideVersionDetails.xhtml:(composite component)
<ui:composition xmlns="http://www.w3.org/1999/xhtml"
xmlns:h="http://java.sun.com/jsf/html"
xmlns:f="http://java.sun.com/jsf/core"
xmlns:cc="http://java.sun.com/jsf/composite"
xmlns:p="http://primefaces.org/ui"
xmlns:ui="http://java.sun.com/jsf/facelets"
xmlns:fn="http://java.sun.com/jsp/jstl/functions"
xmlns:c="http://java.sun.com/jsp/jstl/core">
<cc:interface>
<cc:attribute name="forId" type="java.lang.String" required="true" />
<cc:attribute name="forValue" type="java.lang.Object" />
</cc:interface>
<cc:implementation>
<p:overlayPanel for="#{cc.attrs.forId}" my="left bottom">
#{cc.attrs.forValue}
</p:overlayPanel>
</cc:implementation>
</ui:composition>
Its used in another page:
<h:form>
....
...
<p:dataTable .....>
....
<p:column sortBy="#{dto.isSameCycleOverride}" width="100">
<f:facet name="header">
Override
</f:facet>
<h:commandLink id="overrideCol" binding="#{overrideCol}"
value="#{(dto.isSameCycleOverride) ? 'Yes' : 'No'}" />
<comp:overrideVersionDetails forId="#{overrideCol.clientId}"
forValue="#{dto.message}" />
</p:column>
....
</p:dataTable>
</h:form>
Any help is really appreciated.
I don't work with Primefaces, but with RichFaces I would use :
<comp:overrideVersionDetails forId="#{rich:clientId('overrideCol')}"
forValue="#{dto.message}" />
to do what you want.
With a little Help from SO :
Rich Faces rich:clientId in Primefaces?
it seems you can do this :
...
<h:commandLink id="overrideCol" value="#{(dto.isSameCycleOverride) ? 'Yes' : 'No'}" />
<comp:overrideVersionDetails forId="#{p:component('overrideCol')}"
forValue="#{dto.message}" />
...
Now to see if this works better than the use of binding in a dataTable...

How to fetch validation error messages using FacesContext?

My xhtml contains input fields, where user can input numeric or alphabet values. Using an ajax call I am validating the input value and throwing a validation error on the . But even after entering invalid characters and error message, user may still hit the 'Save' button. Once the user hits the Save button it triggers a method in the Controller. Is there a way I can check for validation errors on p:messages inside the controller using the FacesContext.getCurrentInstance().
xhtml code
<!-- Messages -->
<p:messages id="errorMessages" globalOnly="false" showDetail="true" showSummary="false" closable="true" />
<!-- Column input field-->
<p:column>
<f:facet name="header">
<h:outputText value="Input Amount" escape="false" />
</f:facet>
<p:cellEditor>
<f:facet name="output">
<h:outputText value="#{row.amount}" escape="false">
<f:convertNumber maxFractionDigits="3" minFractionDigits="3"
maxIntegerDigits="5" />
</h:outputText>
</f:facet>
<f:facet name="input">
<p:inputText id="input" value="#{row.amount}" maxlength="10"
size="10">
<f:convertNumber maxFractionDigits="3" minFractionDigits="3"
maxIntegerDigits="5" />
<f:validator validatorId="hourlyValueValidator" for="input" />
<p:ajax event="change" partialSubmit="true" process="input"
update=":#{p:component('errorMessages')}" />
</p:inputText>
</f:facet>
</p:cellEditor>
</p:column>
<!-- Save Button -->
<p:commandButton id="btnSubmit" value="Save"
update=":#{p:component('tblScrollPnl')} :#{p:component('errorMessages')}"
action="#{controller.saveValues()}" ajax="true" />
Controller in ViewScope
public void saveValues() throws Exception {
FacesContext context = FacesContext.getCurrentInstance();
List<FacesMessage> errorMsgList = context.getMessageList("globalMessages");
......
......
......
}
You don't need to get messages from the bean side for validation, as you experienced, view side validation occur but doesn't block your action.
There is couple of thing wrongs in your view, to fix your problem you need to change the process attribute of your p:commandButton, ortherwise only the button is processed (by default process="#this", so the validation is skipped.
<p:commandButton id="btnSubmit" value="Save" process="#form" update=":tblScrollPnl :errorMessages" action="#{controller.saveValues()}" />
Also note that I've removed ajax="true" since it is by default and fixed major problems in update="".
You should also rearrange your validators :
<p:inputText id="input" value="#{row.amount}" maxlength="10" size="10" validator="hourlyValueValidator">
<f:convertNumber maxFractionDigits="3" minFractionDigits="3" maxIntegerDigits="5" />
</p:inputText>

ViewScope instantiate only once

I have the following page, the price.xhtml has been included 3 times.
<f:subview id="include">
<ui:include src="/secure/menu/price.xhtml">
<ui:param name="info" value="#{msg['menu.step3.header']}" />
<ui:param name="domainKey" value="KEY1" />
</ui:include>
</f:subview>
<f:subview id="include2">
<ui:include src="/secure/menu/price.xhtml">
<ui:param name="info" value="#{msg['menu.step3.header']}" />
<ui:param name="domainKey" value="KEY3" />
</ui:include>
</f:subview>
<f:subview id="include2">
<ui:include src="/secure/menu/price.xhtml">
<ui:param name="info" value="#{msg['menu.step3.header']}" />
<ui:param name="domainKey" value="KEY2" />
</ui:include>
</f:subview>
My price.xhtml utilize a ViewScope Mbean (priceMBean), the problem is, JSF only instantiate a single mBean.
I want 3 instances of the priceMBean, how do i achieve this ?
Raphael.
For this typical use case it is better to use injection instead of creating N bean requested scope in the face config
BalusC answers is good and can be improved with DI and facelets.
#ManagedBean
#ViewScoped
public class Parent {
#Inject
private Child price1;
#Inject
private Child price2;
#Inject
private Child price3;
// ...
}
If Child class is always a dependent class of Parent, Child can be annotated as dependent "#Dependent". With dependent, you will have 3 distinct instances of Child class dependent of the lifecycle of the main bean (Parent).
And you can use the following template:
<f:subview id="include">
<ui:include src="/secure/menu/price.xhtml">
<ui:param name="info" value="#{msg['menu.step3.header']}"/>
<ui:param name="domainKey" value="KEY1"/>
<ui:param name="price" value="#{priceMBean.price1}"/>
</ui:include>
</f:subview>
<f:subview id="include2">
<ui:include src="/secure/menu/price.xhtml">
<ui:param name="info" value="#{msg['menu.step3.header']}"/>
<ui:param name="domainKey" value="KEY3"/>
<ui:param name="price" value="#{priceMBean.price2}"/>
</ui:include>
</f:subview>
<f:subview id="include2">
<ui:include src="/secure/menu/price.xhtml">
<ui:param name="info" value="#{msg['menu.step3.header']}"/>
<ui:param name="domainKey" value="KEY2"/>
<ui:param name="price" value="#{priceMBean.price3}"/>
</ui:include>
</f:subview>

Resources