Reputation: 4739
I think my question is similar to this but haven't found it to work
<f:metadata>
<f:viewParam id="id" name="id" value="#{detailsBean.id}"/>
</f:metadata>
Why can't I do this with @Named and utilize CDI:
@Named
@RequestScoped
public class DetailsBean {
private Contacts detailsContact;
@EJB
ContactsFacade contactsEJB;
private int id;
public DetailsBean() {
System.out.println("details bean called");
}
@PostConstruct
public void onLoad() {
detailsContact = contactsEJB.find(id);
}
I'm not able to log the id.
Of course, @ManagedProperty is incompatible with CDI.
*****UPDATE*****
some xhtml:
<?xml version='1.0' encoding='UTF-8' ?>
<!DOCTYPE composition PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<ui:composition xmlns:ui="http://java.sun.com/jsf/facelets"
template="../template.xhtml"
xmlns:h="http://java.sun.com/jsf/html"
xmlns:p="http://primefaces.prime.com.tr/ui"
xmlns:f="http://java.sun.com/jsf/core">
<ui:define name="head">
<f:metadata>
<f:viewParam name="paginator" value="#{contactsBean.contactsTablePaginator}"/>
<f:viewParam name="rows" value="#{contactsBean.contactsTableRows}"/>
</f:metadata>
</ui:define>
<ui:define name="content">
<p:growl id="growl" showDetail="true"/>
<p:panel id="contactsPanel" >
<h:form id ="contactsForm">
<p:dataTable id="contactsTable" value="#{contactsBean.contacts}" selection="#{detailsBean.detailsContact}" var="contacts" widgetVar="contactsTable"
selectionMode="single" rowSelectListener="#{contactsBean.rowSelect}" rowUnselectListener="#{contactsBean.rowUnSelect}"
onRowUnselectUpdate="detailsForm" onRowSelectUpdate="detailsForm"
paginator="#{contactsBean.contactsTablePaginator}" rows="#{contactsBean.contactsTableRows}" rowsPerPageTemplate="5,10,15,25,50,100"
paginatorTemplate="{RowsPerPageDropdown} {FirstPageLink} {PreviousPageLink} {CurrentPageReport} {NextPageLink} {LastPageLink}">
<f:facet name="header">
<p:outputPanel>
<h:outputText value="Search:" />
<p:inputText id="globalFilter" onkeyup="contactsTable.filter()" style="width:150px" />
</p:outputPanel>
</f:facet>
<p:column filterStyle="display:none" filterBy="#{contacts.name}" headerText="Name" style="width:200px">
<h:outputText value="#{contacts.name}" />
</p:column>
<p:column filterStyle="display:none" filterBy="#{contacts.street}" headerText="Street" style="width:280px">
<h:outputText value="#{contacts.street}" />
</p:column>
<p:column filterStyle="display:none" filterBy="#{contacts.city}" headerText="City" style="width:150px">
<h:outputText value="#{contacts.city}" />
</p:column>
<p:column filterStyle="display:none" filterBy="#{contacts.state}" headerText="State" style="width:50px">
<h:outputText value="#{contacts.state}" />
</p:column>
<p:column filterStyle="display:none" filterBy="#{contacts.zip}" headerText="Zip" style="width:100px">
<h:outputText value="#{contacts.zip}" />
</p:column>
<p:column filterStyle="display:none" filterBy="#{contacts.country}" headerText="Country" style="width:150px">
<h:outputText value="#{contacts.country}" />
</p:column>
<p:column filterStyle="display:none" filterBy="#{contacts.sent}" headerText="Sent" style="width:50px">
<h:outputText value="#{contacts.sent}" />
</p:column>
</p:dataTable>
<p:ajaxStatus >
<f:facet name="start">
<h:graphicImage value="../resources/images/ajax-loader-bar.gif" />
</f:facet>
<f:facet name="complete">
<h:graphicImage value="../resources/images/ajax-loader-bar-still.gif" />
</f:facet>
<f:facet name="default">
<h:graphicImage value="../resources/images/ajax-loader-bar-still.gif" />
</f:facet>
</p:ajaxStatus>
<br />
<p:commandLink value="View All" action="#{contactsBean.viewAll}" />
<p:commandLink value="Default View" action="#{contactsBean.viewDefault}" />
<p:commandLink value="Advanced Search" action="search?faces-redirect=true" />
<br />
</h:form>
<br />
</p:panel>
<br />
<br />
<h:form id="detailsForm">
<p:panel id="detailsPanel" visible="#{detailsBean.visible}" >
<h:panelGrid id="detailsPanelGrid" cellpadding="2" cellspacing="2" columns="3" >
<h:outputText value="Name :" />
<p:inputText id="name" value="#{detailsBean.detailsContact.name}" style="width:400px" />
<p:message for="name" />
<h:outputText value="Email :" />
<p:inputText id="email" value="#{detailsBean.detailsContact.email}" style="width:400px" validatorMessage="Must be a valid email address. EX: [email protected]" >
<f:validateRegex pattern="[a-zA-Z0-9]+@[a-zA-Z0-9]+\.[a-zA-Z0-9]+"/>
<p:ajax event="blur" update="emailMsg" />
</p:inputText>
<p:message id="emailMsg" for="email" />
<h:outputText value="Street :" />
<p:inputText id="street" value="#{detailsBean.detailsContact.street}" style="width:400px" />
<p:message for="street" />
<h:outputText value="City :" />
<p:inputText id="city" value="#{detailsBean.detailsContact.city}" style="width:400px" />
<p:message for="city" />
<h:outputText value="State :" />
<p:inputText id="state" value="#{detailsBean.detailsContact.state}" style="width:400px" validatorMessage="Length is greater than 2" >
<f:validateLength maximum="2" />
<p:ajax event="blur" update="stateMsg" />
</p:inputText>
<p:message id="stateMsg" for="state" />
<h:outputText value="Country :" />
<p:inputText id="country" value="#{detailsBean.detailsContact.country}" style="width:400px" />
<p:message for="country" />
<h:outputText value="Phone :" />
<p:inputText id="phone" value="#{detailsBean.detailsContact.phone}" style="width:400px"/>
<p:message for="phone" />
<h:outputText value="Guests :" />
<p:inputText id="guests" value="#{detailsBean.detailsContact.guests}" style="width:400px"/>
<p:message for="guests" />
<h:outputText value="Arrival :" />
<p:calendar id="arrival" value="#{detailsBean.detailsContact.arrival}" showOn="button" />
<p:message for="arrival" />
<h:outputText value="Departure :" />
<p:calendar id="departure" value="#{detailsBean.detailsContact.departure}" showOn="button" />
<p:message for="departure" />
<h:outputText value="Message :" />
<p:inputTextarea id="message" effectDuration="30" style="width:400px;height:100px;" value="#{detailsBean.detailsContact.message}" />
<p:message for="message" />
<h:outputText value="Departure :" />
<p:calendar id="inserted" value="#{detailsBean.detailsContact.inserted}" showOn="button"/>
<p:message for="inserted" />
<h:outputText value="Sent :" />
<h:selectBooleanCheckbox id="sent" value="#{detailsBean.detailsContact.sent}" />
<p:message for="sent" />
<br />
</h:panelGrid>
<p:commandButton value="Submit" action="#{detailsBean.updateContactDetails}" update="contactsForm, growl, stateMsg" />
<p:commandButton value="Close" action="#{detailsBean.handleClose}" update="contactsForm, detailsForm" />
</p:panel>
</h:form>
</ui:define>
</ui:composition>
more java code:
package com.atlanticpkg.view.beans;
import com.atlanticpkg.model.entities.Contacts;
import com.atlanticpkg.util.FacesUtils;
import java.io.Serializable;
import javax.annotation.PostConstruct;
import javax.enterprise.context.RequestScoped;
import javax.enterprise.context.SessionScoped;
import javax.inject.Named;
import javax.faces.application.FacesMessage;
import javax.faces.context.FacesContext;
import javax.inject.Inject;
@Named(value = "detailsBean")
@RequestScoped
public class EditBean {
private Contacts detailsContact;
private boolean visible = false;
@Inject
ContactsBean contactsBean;
public EditBean() {
}
@PostConstruct
public void onLoad() {
}
public void handleClose() {
this.setVisible(false);
this.setDetailsContact(new Contacts());
}
public void updateContactDetails() {
try {
contactsBean.getContactsEJB().edit(detailsContact);
FacesUtils.addMessage(detailsContact.getName() + " was updated successfully!");
} catch (Exception e) {
FacesContext.getCurrentInstance().addMessage(null, new FacesMessage(FacesMessage.SEVERITY_ERROR, "ERROR", e.toString()));
}
}
}
and even more:
@Named(value = "contactsBean")
@RequestScoped
public class ContactsBean {
@Inject
EditBean editBean;
@EJB
private ContactsFacade contactsEJB;
private List<Contacts> contacts = new ArrayList<Contacts>();
private boolean contactsTablePaginator = true;
private int contactsTableRows = 10;
private Contacts selectedContact = new Contacts();
public ContactsBean() {
}
@PostConstruct
public void onLoad() {
updateContactsList();
}
public String viewDefault() {
contactsTablePaginator = true;
contactsTableRows = 10;
return "index?faces-redirect=true&includeViewParams=true";
}
public String viewAll() {
contactsTablePaginator = false;
contactsTableRows = 100;
return "index?faces-redirect=true&includeViewParams=true";
}
public void updateContactsList() {
contacts.clear();
contacts = contactsEJB.findAll();
}
public void rowSelect(SelectEvent event) {
editBean.setVisible(true);
editBean.setDetailsContact((Contacts) event.getObject());
}
public void rowUnSelect(UnselectEvent event) {
editBean.setVisible(false);
editBean.setDetailsContact(new Contacts());
}
}
The inputText boxes populate fine. But soon as I hit submit it says that the values are null. This code works perfectly with SessionScope.
WARNING: /admin/index.xhtml @104,109 value="#{detailsBean.detailsContact.name}": Target Unreachable, 'null' returned null javax.el.PropertyNotFoundException: /admin/index.xhtml @104,109 value="#{detailsBean.detailsContact.name}": Target Unreachable, 'null' returned null
I can see that it's calling the EditBean when I select the data table. It then calls it again when I click the submit button.
Upvotes: 2
Views: 5608
Reputation: 3505
I encountered the exact same problem than you, and solved it by using the external context (containing GET parameters) instead of f:viewParam
.
In your @PostConstruct
method, just get your parameter with something like
FacesContext.getCurrentInstance().getExternalContext().getRequestParameterMap();
Upvotes: 7
Reputation: 6844
The lifecycle doesn't allow your approach.
At first, the bean is created ( constructor ). After that, there is executed dependency injection which is followed by @PostConstruct
method and after that the JSF file is evaluated. And the viewParam
is in that file. So you have to register another listener which is called after filling view params.
I have a solution for @RequestScope
beans, but if the bean's scope is longer ( like View ) then this method is executed after each request ( including AJAX ) which is not probably desired.
Use this for request scope beans:
<f:metadata>
<f:viewParam id="id" name="id" value="#{detailsBean.id}"/>
<f:event type="preRenderView" listener="#{detailsBean.onLoad}" />
</f:metadata>
For @ViewScope
beans I am using this "hack" which works but probably is not best practise. It does same thing but probably it isn't the correct approach.
#{detailsBean.onLoad()}
<f:metadata>
<f:viewParam id="id" name="id" value="#{detailsBean.id}"/>
</f:metadata>
I hope that this is helpful for you.
EDIT:
you are using a lot of AJAX here. This calls have to land in at least ViewScoped
beans. View Scope is similar to RequestScope
, but it takes a quite longer - til the page is left.
But I haven't read it all, there is a lot of code and if the ViewScope doesn't help then maybe you should provide the small piece of problematic code to be chance there to find and focus on the real problem.
Upvotes: 4