I'm trying to render a page, but there is the possibility that some EL Expressions will generate some exceptions.
So I tryed first of all, to sorround by block with a < c:if> in such the way that it shows the code only by checking the critical condition.
But I saw that in case of "error" my page was redirected again as a "HTTP 500 - Internal Server Error".
So I tought that maybe the EL Expression inside the block where computed in any case, also if the < c:if> block where not shown. So I sorrounded my block with a < c:catch> as i read that this block will catch the exceptions. So I also added on all the methods the declaration "throws Exception".
But, again, when the critical condition is not respected, my page will be redirect to the 500 Error page.
I post my XHTML code:
<c:if test="#{!partyBean.emptySet}">
<c:catch>
<p:panel id="panel" style="margin-bottom:10px;">
<f:facet name="header" >
<h:outputLabel value="#{partyBean.currentparty.name}" />
</f:facet>
<f:facet name="actions">
<p:commandButton id="asktojoin" styleClass="ui-panel-titlebar-icon "
action="#{joinRequestBean.askForParty(partyBean.currentparty)}" value="Ask to Join"/>
</f:facet>
<f:facet name="footer" >
<p:commandButton id="pr" action="#{partyBean.previus()}" value="previousParty" rendered="#{partyBean.hasPrevious()}">
</p:commandButton>
<p:commandButton id="nx" style="margin-right:10px" action="#{partyBean.next()}" value="nextParty" rendered="#{partyBean.hasNext()}">
</p:commandButton>
</f:facet>
<h:panelGrid columns="2">
<h:outputLabel value="Symbol:" />
<h:graphicImage value="#{('/partysymbols/'.concat(partyBean.currentparty.symbol))}" width="200" height="171" />
<h:outputLabel for="program" value="Program:" />
<h:outputLabel id="program" value="#{partyBean.currentparty.program}" />
<h:link id="partyname" outcome="memberlist" value="memberlist">
<f:param name="partyname" value="#{partyBean.currentparty.name}" />
</h:link>
</h:panelGrid>
</p:panel>
</c:catch>
</c:if>
<c:if test="#{partyBean.emptySet}">
<h1>There are no parties at the moment</h1></c:if>
</h:form>
</h:body>
And my bean:
#ManagedBean(name="partyBean")
#SessionScoped
public class PartyBean {
#EJB
private PartyManagerLocal ejb;
private PartyDTO[] party;
int i=0;
#PostConstruct
private void init() {
i=0;
refresh();
}
private void refresh(){
Object[] list_o = ejb.getListOfParty().toArray();
party = new PartyDTO[list_o.length];
for(int i=0;i<list_o.length;i++){
party[i]=(PartyDTO)list_o[i];
}
if(i>=list_o.length)
i=list_o.length;
}
public boolean isEmptySet() {
refresh();
return party.length==0;
}
public String next() throws Exception{
refresh();
if(i<party.length-1)
i++;
return "partyview.xhtml?faces-redirect=true";
}
public String previus() throws Exception{
refresh();
if(i>0)
i--;
return "partyview.xhtml?faces-redirect=true";
}
public boolean hasPrevious(){
return i>=1;
}
public boolean hasNext(){
return i<party.length-1;
}
public PartyDTO getCurrentparty() throws Exception{
return party[i];
}
}
I apologize to show to you my whole code, but i have no idea about where is the mistake. Then I also apologize about my horrible code, but at the moment i just need that it works.
The critical condition is that my array should be not empty. Could happen that my Array will be empty but in that case, i need to advise the user about it, instead redirect to the 500 Error page.
Thankyou in advance,
Samuele
You could encapsulate what you want conditionally by surrounding the code in a panelGroup and using the rendered attribute.
Example
<h:panelGroup rendered="#{PartyBean.isEmptySet}">
<!-- Code inside here... -->
<!-- This will render if isEmptySet returns true -->
</h:panelGroup>
Related
I'm trying to conditionally render a commandlink. However I discovered when debugging the bean function stocksView.hasPortfolios is never called. Is this the correct way to user render or should I be doing this in another way?
<h:form id="form">
<p:dataGrid id="prices" var="orderBooks" value="#{stocksView.latestPricesResults}" columns="3" rows="12">
<f:facet name="header">
WST 100
</f:facet>
<p:column>
<p:panel header="#{orderBooks.bidOrderId.member.memberId}">
<h:panelGrid columns="1">
<h:outputText value="#{orderBooks.price}" />
<h:outputText value="#{orderBooks.bidOrderId.member.party}" />
<h:outputText value="#{orderBooks.lastUpdate}" />
<p:commandLink update=":form:buyDetail" oncomplete="PF('buyDialog').show()" title="View Detail">
<h:outputText value="Buy"/>
<f:setPropertyActionListener value="#{orderBooks}" target="#{stocksView.selectedStock}" />
</p:commandLink>
<p:commandLink update=":form:sellDetail" oncomplete="PF('sellDialog').show()" title="View Detail" rendered="#{stocksView.hasPortfolios[orderBooks.bidOrderId.member.memberId]}">
<h:outputText value="Sell"/>
<f:setPropertyActionListener value="#{orderBooks}" target="#{stocksView.selectedStock}" />
</p:commandLink>
</h:panelGrid>
</p:panel>
</p:column>
</p:dataGrid>
</h:form>
This is the hasPortfolios method in StocksView (which is a ViewScoped Bean). The hasPortfolios variable is private Map hasPortfolios;
public void hasPortfolios(){
hasPortfolios = new HashMap<Boolean,String>();
Collection<Portfolio> portfolios = user.getTrader().getPortfolios();
Iterator<Portfolio> iter = portfolios.iterator();
while(iter.hasNext()){
Portfolio p = iter.next();
if(p.getBalance() == 0){
hasPortfolios.put(false, p.getMember().toString());
logger.log(Level.INFO, "hasPortfolios false");
}
else
{
hasPortfolios.put(true,p.getMember().toString());
logger.log(Level.INFO, "hasPortfolios true");
}
}
}
To my eyes you should call the function like this instead of using square brackets:
rendered="#{stocksView.hasPortfolios(orderBooks.bidOrderId.member.memberId)}
Also make sure its public and there is not overloaded version of it.
As usual I was doing a few things wrong. Firstly my map returns a Boolean object in the rendered attribute, and this has to be a boolean primitive. So to get around that I call booleanValue()
rendered="#{stocksView.hasPortfolios[orderBooks.bidOrderId.member.memberId].booleanValue()}"
Also I had my map key/value in the wrong order so the Boolean was actually the key instead of the Member ID.
And finally, I was calling getMember().toString() which returns the Member object as a String, rather than the actual Member ID string which is returned by calling getMember().getMemberId(). So hasPortfolios should actually look like this:
public void hasPortfolios(){
logger.log(Level.INFO, "hasPortfolios start");
hasPortfolios = new HashMap<String,Boolean>();
Collection<Portfolio> portfolios = user.getTrader().getPortfolios();
Iterator<Portfolio> iter = portfolios.iterator();
while(iter.hasNext()){
Portfolio p = iter.next();
if(p.getBalance() == 0){
hasPortfolios.put(p.getMember().getMemberId(),new Boolean(false));
logger.log(Level.INFO, "hasPortfolios false");
}
else
{
hasPortfolios.put(p.getMember().getMemberId(),new Boolean(true));
logger.log(Level.INFO, "hasPortfolios true");
}
}
}
The Sell commandlink is now rendered when there is a portfolio for the user.
Thanks for your help everyone, it pointed me in the right direction.
I'm creating a small application using JSF,facing the exception, below is the code for the form.
<h:form>
<h:selectManyCheckbox value="#{transferMB.selectedItems}">
<f:selectItem itemValue="1" itemLabel="Transfer Status" />
<p:ajax update=":transForm" />
</h:selectManyCheckbox>
</h:form>
exception " javax.faces.view.facelets.TagAttributeException:"
This is a follow-up for issue while loading data
As mentioned there, you need to use EL 2.2 for passing parameter inside EL-Expressions. Seems you don't use that.
So we need another way to get this solved:
<h:form id="transForm">
<p:panelGrid columns="1" rendered="#{transferMB.transFormEnabled}">
<h:outputText value="transForm"/>
</p:panelGrid>
</h:form>
<h:form id="spreadForm">
<p:panelGrid columns="1" rendered="#{transferMB.spreadFormEnabled}">
<h:outputText value="spreadForm"/>
</p:panelGrid>
</h:form>
and in your corresponding bean:
public boolean isTransFormEnabled() {
if (selectedItems.contains("1")) {
return true;
} else {
return false;
}
}
public boolean isSpreadFormEnabled() {
if (selectedItems.contains("2")) {
return true;
} else {
return false;
}
}
You should be calling Boolean-like values into your rendered attributes.
Example:
<p:panelGroup id="group" rendered="{#bean.isOneSelected}">
...
</p:panelGroup>
<p:panelGroup id="group" rendered="{#bean.isTwoSelected}">
...
</p:panelGroup>
And for getting values from selectManyMenu. Please check here.
Also the rendered tag is a Boolean like condition to tell whether a tag should be displayed. You shouldn't need to pass a parameter into that. You should be getting that information from you transferMB
I have a h:inputText with valueChangeListener, when the user type some code another h:inputText display data from MySQL about that code, the valueChangeListener works but the second h:inputText not displayed the value and only do it when I set the readonly attribute or I change the component to h:outputText
my facelets page is:
<h:form id="idFacturacion">
<rich:panel>
<f:facet name="header">
<h:outputText value="FACTURACION AL CLIENTE" />
</f:facet>
<h:panelGrid columns="4">
<h:outputText value="Cedula: " />
<h:inputText value="#{facturaBean.encFactura.cedula}" onchange="submit();" valueChangeListener="#{facturaBean.processValueChange}" />
<h:outputText value="Nombre: " />
<h:inputText value="#{facturaBean.encFactura.nombre_cli}" />
</h:panelGrid>
</rich:panel>
</h:form>
facturaBean is:
#ManagedBean
#SessionScoped
public class FacturaBean {
private EncFactura encFactura = new EncFactura();
//getter and setter
public void processValueChange(ValueChangeEvent event){
String ced = event.getNewValue().toString();
try{
//do the database thing
if(resultSet.next()){
encFactura.setNombre_cli(resultSet.getString("nombre_cli"));
}else{
encFactura.setNombre_cli("");
}
}catch(SQLException error){
facesContext.addMessage(null, new FacesMessage("Hubo un error SQL."));
}
}
}
Please see
Change inputText value from listener method… and
Possible to execute `valueChangeListener` for `p:inputText` without hitting `enter` key?
May I suggest using ajax?
Here is a primefaces example but you could apply to richfaces..
<h:inputText value="#{facturaBean.stringOne}" >
<p:ajax event="change" listener="#{facturaBean.processValueChange}" update="strTwo"/> </h:inputText> <h:outputText value="Nombre: " />
<h:inputText id="strTwo" value="#{facturaBean.stringTwo}" />
</h:panelGrid>
private String stringOne= "";
private String stringTwo= "";
public void processValueChange(){
stringTwo = stringOne;
}
With getters etc.. basically on change, fires off to ajax, you do your database call etc, then it returns the response and updates your other input field, it's a much cleaner way than trying to submit forms etc..
Also are you sure you want session scope?
I have a h:datatable showing a list of rows, and the fields of each row are input fields.
I render an "Add Row" button before the table, and a "Remove Row" button on each row of the table.
The baking bean is viewScoped, and the buttons add/remove elements from the java list in the backing bean, and then return to the same view.
I set the immediate attribute to "true" in the buttons in order to not validate the input fields when I add or remove a row.
Everything works ok but one thing: the values of the input fileds are cleared. I thought that the view kept the values beacuse the bean is viewScoped.
How can I achieve adding/removing rows without triggering validations and keeping the values that were already typed by the user in the form?
My view:
<h:form>
<h:commandButton value="Añadir Fila" immediate="true" action="#{tablaController.addRowAction}" />
<h:dataTable value="#{tablaController.lista}" var="fila" cellpadding="0" cellspacing="0" border="1">
<f:facet name="header">TABLA</f:facet>
<h:column>
<f:facet name="header"><h:outputLabel value="NOMBRE" /></f:facet>
<h:inputText id="nom" value="#{fila.nombre}" />
<h:message for="nom" class="msjError" />
</h:column>
<h:column>
<f:facet name="header"></f:facet>
<h:commandButton value="Quitar Fila" immediate="true" action="#{tablaController.removeRowAction(fila)}" />
</h:column>
</h:dataTable>
</h:form>
My backing bean:
#ManagedBean(name="tablaController")
#ViewScoped
public class TablaController {
private List<Fila> lista;
...
public TablaController() { }
...
#PostConstruct
public void init() {
this.lista = new ArrayList<Fila>();
for (int i=0; i<5; i++) {
Fila fila = new Fila();
fila.setNombre("");
this.lista.add(i,fila);
}
}
...
public String addRowAction () {
Fila fila = new Fila();
fila.setNombre("");
this.lista.add(fila);
return "";
}
public String removeRowAction (Fila f) {
boolean exito = this.lista.remove(f);
return "";
}
...
}
UPDATE --> MY SOLUTION:
I write here my solution if someone is interested.
The problem is that I use immediate="true" to skip validations, but this makes to skip the update_model_values too, so that the values entered by the user in the form are lost after clicking the add/remove buttons and re-redenring the page.
As I use "JSR-303 bean validation", my solution was to skip validations using the f:validateBean to enable/disable them. Depending on the button I click, if I want the validations to execute, I enable the bean validation (for example in a "submit" button), and if I want to skip them, I disable bean validation (like in the add/remove row buttons). But anyway the update_model_values always executes, so the values are not lost.
Here's the view:
<h:form>
<f:validateBean disabled="#{!empty param['disableValidation']}">
<h:commandButton value="Añadir Fila" action="#{tablaController.addRowAction}">
<f:param name="disableValidation" value="true" />
</h:commandButton>
<h:dataTable value="#{tablaController.lista}" var="fila" cellpadding="0" cellspacing="0" border="1">
<f:facet name="header">TABLA</f:facet>
<h:column>
<f:facet name="header"><h:outputLabel value="NOMBRE" /></f:facet>
<h:inputText id="nom" value="#{fila.nombre}" />
<h:message for="nom" class="msjError" />
</h:column>
<h:column>
<f:facet name="header"></f:facet>
<h:commandButton value="Quitar Fila" action="#{tablaController.removeRowAction(fila)}">
<f:param name="disableValidation" value="true" />
</h:commandButton>
</h:column>
</h:dataTable>
<h:commandButton value="Submit" action="#{tablaController.saveData}" />
</f:validateBean>
</h:form>
The backing bean:
#ManagedBean(name="tablaController")
#ViewScoped
public class TablaController {
private List<Fila> lista;
...
public TablaController() { }
...
#PostConstruct
public void init() {
this.lista = new ArrayList<Fila>();
for (int i=0; i<5; i++) {
Fila fila = new Fila();
fila.setNombre("fila "+i);
this.lista.add(i,fila);
}
}
...
public String addRowAction () {
Fila fila = new Fila();
fila.setNombre("");
this.lista.add(fila);
return "";
}
public String removeRowAction (Fila f) {
this.lista.remove(f);
return "";
}
...
public String saveData () {
...
//processes the valid data
//for example, calls to a service method to store them in a database
...
return "";
}
...
}
I set the immediate attribute to "true" in the buttons in order to not validate the input fields when I add or remove a row.
immediate="true" is the wrong tool for the job. It should be used to prioritize validation, not to enable/disable validation. The difference is rather huge as you encountered yourself.
You want to trigger validation conditionally. In case of e.g. required="true" that'd be as easy as
<h:inputText ... required="#{saveButtonPressed}" />
where #{saveButtonPressed} evaluates true when the save button is pressed. E.g. when its client ID is present in request parameter map.
In case of JSR 303 bean validation, that'd be a matter of
<f:validateBean disabled="#{not saveButtonPressed}">
<h:inputText ... />
</f:validateBean>
or with OmniFaces <o:validateBean> which allows controlling that on a per-command basis.
<h:commandButton id="add" ...>
<o:validateBean disabled="true" />
</h:commandButton>
I had exactly the same problem. In short, you can NOT use immediate for action that update data table(UIData) or facelet repeat. Short explanation:submitted values are not kept for re-display if inputs in UIData do not go through validation. Long explanation can be found here: long explanation and a related bug in Mojarra
i have the following bean:
public class MyBean {
public ArrayList<ReportRow> getReportRows()
{
return reportRows;
}
private final ArrayList<ReportRow> reportRows =
new ArrayList<ReportRow>(Arrays.asList(
new ReportRow("","")
));
public ArrayList<ReportRow> getOrderList() {
return reportRows;
}
public String addAction() {
ReportRow row = new ReportRow("", "");
reportRows.add(row);
return null;
}
public class ReportRow{
String reportColumnName;
String reportColumnDesc;
public ReportRow(String reportColumnName,String reportColumnDesc) {
this.reportColumnName=reportColumnName;
this.reportColumnDesc=reportColumnDesc;
}
public String getReportColumnName()
{
return reportColumnName;
}
public void setReportColumnName(String reportColumnName)
{
this.reportColumnName = reportColumnName;
}
public String getReportColumnDesc()
{
return reportColumnDesc;
}
public void setReportColumnDesc(String reportColumnDesc)
{
this.reportColumnDesc = reportColumnDesc;
}
}
}
jsf page:
<t:dataTable value="#{myBean.reportRows}" var="o"
id="reportColumnsTable" styleClass="standardTable" headerClass="standardTable_Header"
rowStyleClass="#{myBean.viewDelayedRsd}"
>
<h:column>
<t:outputLabel value="Column name:"></t:outputLabel>
<t:inputText id="ReportColumnName" value="#{o.reportColumnName}" required="true">
</t:inputText>
</h:column>
<h:column>
<t:outputLabel value="Column Desc:"></t:outputLabel>
<t:inputText id="ReportColumnDesc" value="#{o.reportColumnDesc}" >
</t:inputText>
</h:column>
<h:column>
<h:outputLink value="#add"><h:outputText value="Add"/>
<a4j:support ajaxSingle="true" event="onclick" action="#{rprtBean.addAction}"
reRender="reportColumnsTable,msgPanel" />
</h:outputLink>
</h:column>
</t:dataTable>
problem is that when i click on add, it generates a new row, and clear the old one, and i want to maintain the values of old row, any ideas ?
You're using a <h:outputLink> instead of a <h:commandLink>. The <h:outputLink> doesn't submit the form at all, it fires a plain GET request. The <a4j:support> won't work properly inside a <h:outputLink>. Replace it by a <h:commandLink>:
<h:commandLink value="Add" action="#{rprtBean.addAction}">
<a4j:support reRender="reportColumnsTable,msgPanel" ajaxSingle="true" />
</h:commandLink>
Then, you need to ensure that you preserve the data model for subsequent request in case that your bean is request scoped. There are several ways to achieve this:
Set either Tomahawk datatable's preserveDataModel to true:
<t:dataTable preserveDataModel="true">
Or save the bean state in the view scope. Add the following tag somewhere in the page:
<t:saveState value="#{myBean}" />
or since you're also using RichFaces/Ajax4jsf:
<a4j:keepAlive beanName="myBean" />
i just used the a4j command link and everything worked fine.