How to show validator's message for specific UI component? - jsf-2

Unable to show faces message in xhtml page - its showing in console.
In forgotPassword link, like to check if user exist or not
<h:outputText value="Enter User Name" />
<h:inputText value="#{loginBean.technicianName}" required="true"
requiredMessage="user name is required" id="unameId" >
<f:validator validatorId="com.beans.UserNameAvailableValidator" />
<f:ajax event="blur" render="username_message" />
</h:inputText>
<rich:message for="unameId" id="username_message"/>
bean code:
#FacesValidator("com.beans.UserNameAvailableValidator")
#RequestScoped
public class UserNameAvailableValidator implements Validator {
UserdetailsDAO userdetailsDAO = null;
#Override
public void validate(FacesContext fc, UIComponent uic, Object value) throws ValidatorException {
String userName = (String) value;
userdetailsDAO = new UserdetailsDAOImpl();
try {
if(userdetailsDAO.getUserdetails(userName)!= null) {
System.out.println("user exist");
} else {
throw new ValidatorException(new FacesMessage("Username doesnot exist "));
}
} catch(Exception e) {
e.printStackTrace();
}
}
}

You are only creating the message, you also need to add put it somewhere (the message does not work the same way as exception), in this case you add it to the context:
FacesContext fc = FacesContext.getCurrentInstance();
UIComponent root = fc.getViewRoot();
UIComponent component = root.findComponent("unameId");
fc.addMessage(component.getClientId(fc), new FacesMessage("Username does not exist."));

Related

JSF viewAction passing param and it gets set, but returns to null

JSF 2.2
Primefaces 4.0
JBoss Wildfly
From a page with a list of customers, and want a button for each customer where the user can add items.
When I click the "New Item" button I am redirected to the new item page.
In the url is the customer id
newItem.jsf;jsessionid=Xw7tdljr9f0atzyET2Fy6_WI?customerId=3
I can debug that the set customer id method in the new item bean in called with the value 3, nice :)
But right after I debug that the get customer id method is called.. and now the customer id is null :(
And I made a syso :
18:10:25,312 INFO [stdout] (default task-9) Setting customer id 3
So the customer id is begin set... but is reset to null somehow ????
customers.xhtml
<ui:define name="content">
<f:metadata>
<f:viewParam name="customerId" value="#{customerController.customerEnt.id}" />
</f:metadata>
<h:form id="customers" prependId="false" includeViewParams="true">
<p:dataTable id="dataTable" var="customer"
value="#{customerController.customers}" rowKey="#{customer.id}"
styleClass="userDataTableStyle" paginator="true" rows="10"
selection="#{customerController.selectedCustomers}"
paginatorTemplate="{CurrentPageReport} {FirstPageLink} {PreviousPageLink} {PageLinks} {NextPageLink} {LastPageLink} {RowsPerPageDropdown}"
lazy="true" rowsPerPageTemplate="10,15,50">
...
<p:column>
<p:commandButton ajax="false" value="New Item" action="#{customerController.newItem(customer)}"/>
</p:column>
</p:dataTable>
</h:form>
newItem.xhtml
<ui:define name="content">
<f:metadata>
<f:viewParam name="customerId"
value="#{newItemController.customerId}" />
<f:viewAction action="#{newItemController.init()}"/>
</f:metadata>
<h:form id="item" includeViewParams="true">
...
newItemController.java
#SuppressWarnings("serial")
#ViewScoped
#Named
public class NewItemController implements Serializable {
private CustomerEnt customerEnt;
private String customerId;
#PostConstruct
public void init() {
itemEnt = new ItemEnt();
if (customerId == null) {
String message = "Bad request. Please use a link from within the system.";
FacesContext.getCurrentInstance().addMessage(null, new FacesMessage(FacesMessage.SEVERITY_ERROR, message, null));
return;
}
customerEnt = customerDas.find(Long.parseLong(customerId));
if (customerEnt == null) {
String message = "Bad request. Unknown customer.";
FacesContext.getCurrentInstance().addMessage(null, new FacesMessage(FacesMessage.SEVERITY_ERROR, message, null));
}
}
public String getCustomerId() {
return customerId;
}
public void setCustomerId(String customerId) {
this.customerId = customerId;
System.out.println("Setting customer id " + customerId);
}
}
CustomerController.java
#SuppressWarnings("serial")
#SessionScoped
#Named
public class CustomerController implements Serializable {
private Long customerId;
public String newItem(CustomerEnt customerEnt) {
customerId = customerEnt.getId();
return "newItem?faces-redirect=true&customerId=" + customerId;
}
As L-Ray stated, the init was called twice, so I made this change in NewItemController:
public void init() {
System.out.println("In init");
}
#PostConstruct
public void postConstruct() {
itemEnt = new ItemEnt();
System.out.println("In postConstruct");
}
public void loadData() {
if (customerId == null) {
String message = "Bad request. Please use a link from within the system.";
FacesContext.getCurrentInstance().addMessage(null, new FacesMessage(FacesMessage.SEVERITY_ERROR, message, null));
return;
}
}
public void save() throws Exception {
try {
serviceSLSB.save(Long.parseLong(customerId), itemEnt);
FacesMessage m = new FacesMessage(FacesMessage.SEVERITY_INFO, "Saved!", "Item saved successful");
facesContext.addMessage(null, m);
postConstruct();
} catch (ConstraintViolationException e) {
itemEnt.setBid(null);
String errorMessage = getRootErrorMessage(e);
FacesMessage m = new FacesMessage(FacesMessage.SEVERITY_ERROR, errorMessage, "Saving unsuccessful");
facesContext.addMessage(null, m);
} catch (Exception e) {
String errorMessage = getRootErrorMessage(e);
FacesMessage m = new FacesMessage(FacesMessage.SEVERITY_ERROR, errorMessage, "Saving unsuccessful");
facesContext.addMessage(null, m);
}
}
and in the newItem.xhtml
<f:metadata>
<f:viewParam name="customerId"
value="#{newItemController.customerId}" />
<f:viewAction action="#{newItemController.loadData()}"/>
</f:metadata>
And now it works... :) but now I have a new problem.. i will create a separate question for that :)
Thanks for the help
The given source looks good - just one thing caught my eyes: At the moment, your NewItemController.init() get's called twice
as #PostConstruct
through f:viewAction
If you call the method anyway, you don't need the annotation, isn't it?
i will never understand f:viewParam... maybe you miss includeViewParams=true in CustomerController.newItem()? never saw on a form, maybe it is JSF 2.2
i am doing it this way:
#ViewScoped
#Named
public class NewItemController implements Serializable
{
private CustomerEnt customerEnt;
#ManagedProperty("#{param.customerId}")
private String customerId;
#PostConstruct
public void init()
{
if(customerId == null)
{
String message = "Bad request. Please use a link from within the system.";
FacesContext.getCurrentInstance().addMessage(null, new FacesMessage(FacesMessage.SEVERITY_ERROR, message, null));
return;
}
customerEnt = customerDas.find(Long.parseLong(customerId));
if(customerEnt == null)
{
String message = "Bad request. Unknown customer.";
FacesContext.getCurrentInstance().addMessage(null, new FacesMessage(FacesMessage.SEVERITY_ERROR, message, null));
}
}
public String getCustomerId()
{
return customerId;
}
public void setCustomerId(String customerId)
{
this.customerId = customerId;
System.out.println("Setting customer id " + customerId);
}
}
and newItem.xhtml
<ui:define name="content">
<!--
<f:metadata>
<f:viewParam name="customerId"
value="#{newItemController.customerId}" />
<f:viewAction action="#{newItemController.init()}"/>
</f:metadata>
-->
<h:form id="item">
...
</ui:define>

GET parameters not being passed to ViewScoped ManagedBean

I have a p:dataTable with p:contextMenu and some p:menuitems. One of these menu items should pass on an id to another view which is read like pointed out here.
The thing is the converter throws the required message like the id wasn't sent - and it seems like it truly isn't. I think I'm missing something basic, but I really couldn't figure it out. Here's the code:
The source view
<h:form id="formTabela">
<p:fieldset>
<p:dataTable id="sistemas"
selection="#{sistemaMb.sistemaSelecionado}">
(...)
</p:dataTable>
</p:fieldset>
<p:contextMenu for="sistemas">
<p:menuitem value="Gerenciar módulos" icon="ui-icon-search"
action="modulos?faces-redirect=true&includeViewParams=true"
ajax="false">
<f:param name="id" value="#{sistemaMb.sistemaSelecionado.id}"/>
</p:menuitem>
(More items...)
</p:contextMenu>
(Some dialogs...)
</h:form>
Target view (modulos)
<!-- This is on body: -->
<ui:define name="metadata">
<f:metadata>
<f:viewParam name="id" value="#{moduloMb.sistema}"
converterMessage="foo"
required="true"
requiredMessage="bar"/>
<f:event type="preRenderView" listener="#{moduloMb.init()}" />
</f:metadata>
</ui:define>
Target view managed bean
#ManagedBean
#ViewScoped
public class ModuloMb implements Serializable {
private Sistema sistema;
#PostConstruct
public void init() {
if (!Faces.isPostback() && !Faces.isValidationFailed()) {
// business stuff, but "sistema" is always null.
}
}
public Sistema getSistema() {
return sistema;
}
public void setSistema(Sistema sistema) {
this.sistema = sistema;
}
(...)
}
The converter
#FacesConverter(forClass = Sistema.class)
public class SistemaConverter implements Converter {
private final SistemaService sistemaService = lookup(SistemaService.class);
#Override
public Object getAsObject(FacesContext context, UIComponent component,
String value) {
if (value == null || !value.matches("\\d+")) {
return null;
}
Optional<Sistema> optSistema = sistemaService.find(Short.valueOf(value));
if (!optSistema.isPresent())
throw new ConverterException(
new FacesMessage("Id de sistema inválido " + value));
return optSistema.get();
}
#Override
public String getAsString(FacesContext context, UIComponent component,
Object value) {
if (!(value instanceof Sistema) || ((Sistema) value).getId() != null) {
return null;
}
return ((Sistema) value).getId().toString();
}
}
The includeViewParams directive which you use in the outcome string for the p:menuitem tells JSF to insert the special set of view parameters as request parameters in the GET request to your target view.
BUT, f:param does not define a view param and neither will it be appended to the URL to which the GET request is done.
It does work if you append the parameter directly to the implicit navigation outcome: "modulod?faces-redirect=true&id=..."

PrimeFaces picklist target not populated

I'm implementing a PrimeFaces picklist in a dialog. Everytime the dialog is shown the contents of the target of the picklist should change depending on a list entry shown before. Before I open the dialog I fill the target of the picklist in ProdukteBean.onEditProdukt(..) with the appropriate values. Unfortunately these target values do not show up in the target container. Here are the relevant code pieces:
list.xhtml:
<p:commandLink id="editButton" update=":dialogForm:editDialogPanel" title="Edit"
oncomplete="produktDialog.show();"
process="#this" partialSubmit="true"
action="#{produkteBean.onEditProdukt}">
<h:outputText value="Bearbeiten" />
<f:setPropertyActionListener value="#{p}" target="#{produkteBean.produkt}" />
</p:commandLink>
dialog.xhtml:
<!-- ... -->
<p:dialog id="dialog" header="Produkt-Details" widgetVar="produktDialog" appendToBody="true" showEffect="explode" hideEffect="explode" modal="true" width="500">
<p:messages id="msgs"/>
<h:form id="dialogForm">
<!-- ... -->
<p:pickList id="produkteDatenList" var="proddat" value="#{produkteBean.datenList}"
itemLabel="#{proddat.bezeichnung}" itemValue="#{proddat}"
converter="produktDatConverter"/>
<!-- ... -->
</h:form>
</p:dialog>
ProdukteBean.java:
#Named("produkteBean")
#ViewScoped // #SessionScoped // #ViewScoped
public class ProdukteBean implements Serializable {
#Inject #Transient private ProdukteService produkteService;
#Inject #Transient private DatenService datenService;
#Inject()
private ProdukteDatenBean produkteDatenBean;
private DualListModel<Dat> datenList = new DualListModel<Dat>();
private Dat dat = null;
public ProdukteBean() {
}
#PostConstruct
private void init() {
getAll();
}
private void getAll() {
logger.debug("getAll()");
getAllProdukte();
getAllDaten();
}
private void getAllDaten() {
logger.debug("getAllDaten()");
List<Dat> source = new ArrayList<Dat>();
source.addAll(datenService.list());
List<Dat> target = new ArrayList<Dat>();
if (produkt.getDaten() != null) {
logger.debug("adding " + produkt.getDaten().size() + " daten to produkt " + produkt.getName());
target.addAll(produkt.getDaten());
}
DualListModel<Dat> datenList = new DualListModel<Dat>();
datenList.setSource(source);
datenList.setTarget(target);
setDatenList(datenList);
}
public List<Produkt> getAllProdukte() {
logger.debug("getAllProdukte()");
return produkteService.list();
}
public void onEditProdukt() {
onEditProdukt(null);
}
public void onEditProdukt(ActionEvent actionEvent) {
logger.debug("onEditProdukt: " + ReflectionToStringBuilder.toString(produkt));
if (produkt != null) {
setSelectedEinheit(produkt.getEinheit());
getAllDaten();
}
FacesMessage msg = new FacesMessage("Produkt ausgewählt", produkt.getName());
FacesContext.getCurrentInstance().addMessage(null, msg);
}
/**
* #return the einheitList
*/
public List<Einheit> getEinheitList() {
if (einheitList == null) {
einheitList = produkteService.getEinheiten();
}
return einheitList;
}
}
ProduktDatConverter.java:
#FacesConverter(forClass=Dat.class,value="produktDatConverter")
#ViewScoped
public class ProduktDatConverter implements Converter {
#Inject
#Transient DatenService datenService;
#Transient
protected final Logger logger = Logger.getLogger(getClass().getName());
// gets never called (of course)
public Object getAsObject(FacesContext arg0, UIComponent arg1, String str) {
logger.debug("getAsObject(): " + str);
return null;
}
public String getAsString(FacesContext arg0, UIComponent arg1, Object object) {
if (object instanceof Dat) {
// logger.debug(" returning id " + String.valueOf(((Dat) object).getId()));
return Long.toString(((Dat) object).getId());
}
return null;
}
}
Any ideas? Many thanks in advance!
You are using #ViewScoped along CDI Managed Bean. Change it to JSF Managed Bean. Better, use CODI instead
Also see:
View Scope in CDI Weld
CDI missing #ViewScoped and #FlashScoped
I suppose it's converter + injection problem. Please, click here and refer to the BalusC answer. You can also try to replace:
#FacesConverter(forClass=Dat.class,value="produktDatConverter")
#ViewScoped
with
#ManagedBean
#RequestScoped
and call the converter like this:
converter="#{produktDatConverter}"

Conversation Scoped bean for same view

I have a DTO which has a list. I want to add new rows to datatable when user clicks add button. But when I click add the dto i.e constructor is called and value is initialized and list size is 0. The bean is conversation scoped. Should I start and end conversation for same view while using conversation scoped bean? I am using same bean for edit and it is working well. How to solve initialization problem while using richfaces 4 and jsf 2 and ajax.
View:
<rich:panel id ="dataPnl">
<rich:dataTable value="#{legendbean.legendDTO.list}" var="legend" style="width:100%">
<rich:column>
<f:facet name="header">
<h:outputText value="SN"/>
</f:facet>
<h:inputText value="#{legend.sn}"/>
</rich:column>
<rich:column>
<f:facet name="header">
<h:outputText value="Description"/>
</f:facet>
<h:inputText value="#{legend.desc}"/>
</rich:column>
<rich:column>
<a4j:commandLink value="Add" actionListener="#{legendbean.addLegendRange()}" render="nisForm:dataPnl"/>
<h:outputText value=" / "/>
<a4j:commandLink value="Remove" actionListener="#{legendbean.removeLegendRange(legend)}" render="nisForm:dataPnl"/>
</rich:column>
</rich:dataTable>
</rich:panel>
Bean :
#Named("legendbean")
#ConversationScoped
public class LegendController implements Serializable {
LegendDTO legendDTO = new LegendDTO();
String selectedLegend;
boolean edit;
#Inject
private Conversation conversation;
public boolean isEdit() {
return edit;
}
public void setEdit(boolean edit) {
this.edit = edit;
}
public LegendController() {
Logger.getLogger(LegendController.class.getName()).warning("The value of Edit is : " + edit);
if (!edit) {
legendDTO.getList().add(new Legend());
Logger.getLogger(LegendController.class.getName()).warning("The size of list" + legendDTO.getList().size());
}
}
public LegendDTO getLegendDTO() {
return legendDTO;
}
public void setLegendDTO(LegendDTO legendDTO) {
this.legendDTO = legendDTO;
}
public void addLegendRange() {
Logger.getLogger(LegendController.class.getName()).warning("List Size " + legendDTO.getList().size());
legendDTO.getList().add(new Legend());
Logger.getLogger(LegendController.class.getName()).warning("List Size " + legendDTO.getList().size());
}
public void removeLegendRange(Legend legend) {
if (legendDTO.getList().size() != 1) {
legendDTO.getList().remove(legend);
}
}
public String saveLegend() {
Logger.getLogger(LegendController.class.getName()).warning("Save Legend Edit" + edit);
LegendDAO dao = new LegendDAO();
if (dao.addLegend(legendDTO, edit)) {
if (edit) {
conversation.end();
edit = false;
Logger.getLogger(LegendController.class.getName()).warning("Save Legend Edit" + edit);
return "VIEWLEGEND";
} else {
legendDTO = new LegendDTO();
legendDTO.getList().add(new Legend());
FacesContext.getCurrentInstance().addMessage(null, new FacesMessage("Saved !"));
return "";
}
} else {
FacesContext.getCurrentInstance().addMessage(null, new FacesMessage("Could Not Save Confim if you have already defined Legend " + legendDTO.getLegendName() + "!"));
return "";
}
}
public List<LegendDTO> getLegends() {
LegendDAO dao = new LegendDAO();
return dao.getLegendDTO();
}
//All function from here are for legend delete
public void deleteLegendType(LegendDTO dto) {
LegendDAO dao = new LegendDAO();
if (dao.deleteLegendType(dto.getLegendName())) {
FacesContext.getCurrentInstance().addMessage(null, new FacesMessage("Deleted !"));
} else {
FacesContext.getCurrentInstance().addMessage(null, new FacesMessage("Deleted Error !"));
}
}
//All function from here is to legend edit
public String editLegendType(LegendDTO dto) {
conversation.begin();
edit = true;
legendDTO = dto;
LegendDAO dao = new LegendDAO();
dto.getList().clear();
try {
List<Legend> legends = dao.getDetailForEditLegend(dto.getLegendName());
dto.setList(legends);
} catch (SQLException ex) {
Logger.getLogger(LegendController.class.getName()).warning("SQL EXception has occoured");
}
Logger.getLogger(LegendController.class.getName()).warning("The size of list" + dto.getList().size());
return "addLegend";
}
public String cancel() {
conversation.end();
return "VIEWLEGEND";
}
}
Yes, you need to start a long-running conversation in order to make your conversation (and conversation scoped beans) span multiple requests. Otherwise conversation gets killed at the end of a JSF request (conversation is transient by default: refer to ConversationScoped javadoc).
Also a common solution in such cases as yours is to use ViewScoped beans, but the annotation is JSF2 specific and is not presented in CDI (you can port it to CDI or use seam-faces module, more details: http://www.verborgh.be/articles/2010/01/06/porting-the-viewscoped-jsf-annotation-to-cdi/).
If you're not constrained to using CDI/Seam annotations, you can change your bean to use #ManagedBean(name="legendbean") from the javax.faces.bean.ManagedBean package and then use a #ViewScoped annotation on your class that guarantees that as long as the user is on the same page, you'll be using the same instance of the managed bean. Nothing else needs to change at all with your setup, all #Injects will work as normal. To initialize the backing legendDTO.list, annotate a method in your ViewScoped JSF bean with #PostConstruct JSF annotation and put the list population logic in there. You can safely add/remove to the list without it being re-initialized to empty. But you must remember to commit the changes to this list back to the database.
Just a thought, you might want to show a popup that will allow your users confirm they want to delete anything from your db, as safe practice. Cheers

The value returned by a h:selectOneMenu / f:selectItems is always null for a bean

I'm still trying to program an app with jsf2, ejb3.1, cdi and glassfish.
I have a form which have a selectOneMenu
<h:form prependId="false">
...
<f:validateBean>
...
<h:selectOneMenu value="#{bottleManagedBean.selectProducer}" id="selectproducerb"
validatorMessage="#{messages.bottleaddinvalideproducer}" immediate="true">
<f:converter binding="#{producerConverter}"/>
<f:selectItems value="#{bottleManagedBean.producerItems}" />
</h:selectOneMenu>
...
The of the selectItems component are well showned but when I submit the form the value of bottleManagedBean.selectProducer is always null.
My formbean
#Named("bottleManagedBean")
#RequestScoped
public class BottleManagedBean {
....
private List<Producer> producers;
public List<Producer> getProducers() {
if (producers == null) {
setProducers(producerService.list(Producer.class));
}
return producers;
}
public void setProducers(List<Producer> producers) {
this.producers = producers;
}
private Producer selectProducer;
public Producer getSelectProducer() {
return selectProducer;
}
private List<SelectItem> producerItems;
public List<SelectItem> getProducerItems() {
if (producerItems == null) {
producerItems = new ArrayList<SelectItem>();
for (Producer current : getProducers()) {
producerItems.add(new SelectItem(current.getId(), current.getName()));
}
}
return producerItems;
}
public void setProducerItems(List<SelectItem> producerItems) {
this.producerItems = producerItems;
}
...
The converter
#Named("producerConverter")
public class ProducerConverter implements Converter {
#Inject
BusinessService<Producer> service;
private static Logger trace = Logger.getLogger(ProducerConverter.class.getCanonicalName());
#Override
public Object getAsObject(FacesContext fc, UIComponent uic, String id) {
try {
return service.findByID(Producer.class, Integer.parseInt(id));
} catch (NumberFormatException e) {
e.printStackTrace();
throw new ConverterException(e);
}
}
#Override
public String getAsString(FacesContext fc, UIComponent uic, Object o) {
String asString = null;
if (o != null) {
asString = String.valueOf(o);
}
return asString;
}
}
I tried to debug the app .When I submit the form , the application never goes to the setter.
I also tried to add a valuechangelistener and my app never called this method.
Finally, I tried to submit an integer (eg. the id of my bean) and the value is well filled when I submit.1
So,... what's wrong ?
Thanks in advance for your help
here is how you should use the valuechangelistener properly in jsf2
Add <f:ajax listener="#{bottleManagedBean.selectProducer}" /> to your <h:selectOneMenu
Like this:
<h:selectOneMenu value="#{bottleManagedBean.selectProducerValueChange}" id="selectproducerb"
validatorMessage="#{messages.bottleaddinvalideproducer}">
<f:ajax listener="#{bottleManagedBean.selectProducerValueChange}" />
<f:converter binding="#{producerConverter}"/>
<f:selectItems value="#{bottleManagedBean.producerItems}" />
</h:selectOneMenu>
and implement the selectProducerValueChange in your bean...

Resources