I have a button in a form and I want an error message to be displayed when I click on this button. It is a step I want to complete before coding something similar. My code does not work because the error message is not displayed when I click on the button.
My form is:
<h:form id="myForm">
<p:messages id="errorMessage" for="myForm" autoUpdate="true" />
<p:fieldset id="myFieldSet"
style="margin-left:auto ; margin-right:auto ; width:98% ; height:90px;">
<p:outputLabel for="numSi"
value="Value :"
style="margin-left:31px;margin-top:25px;" />
<p:inputText id="numSi"
value="#{suppSiBean.researchValue}"
maxlength="9" required="true">
</p:inputText>
<p:commandButton id="suppSignaButton" type="submit" ajax="true"
value="Launch"
style="text-align: center ; height:45px; width:150px ; margin-top:20px;"
action="#{suppSiBean.lancerRequete()}" />
</p:fieldset>
</h:form>
Excerpt of my bean :
public void lancerRequete() {}
FacesContext context = FacesContext.getCurrentInstance();
//I'm intentionally hide the values of the three following variables because it's confidential
ResourceBundle bundle = ...
String message = ...
String messageFormat = ...
FacesMessage facesMessage = new FacesMessage(FacesMessage.SEVERITY_ERROR, messageFormat.toString(), "");
FacesContext.getCurrentInstance().addMessage(getClientId("myForm"), facesMessage);
}
public String getClientId(String id) {
FacesContext context = FacesContext.getCurrentInstance();
UIViewRoot root = context.getViewRoot();
UIComponent c = findComponent(root, id);
LOGGER.info("c.getClientId(context) vaut :" + c.getClientId(context));
return c.getClientId(context);
}
private UIComponent findComponent(UIComponent c, String id) {
if (id.equals(c.getId())) {
return c;
}
Iterator<UIComponent> kids = c.getFacetsAndChildren();
while (kids.hasNext()) {
UIComponent found = findComponent(kids.next(), id);
if (found != null) {
return found;
}
}
return null;
}
Why not targeting the ID of the component directly in the addMessage method ?
public void lancerRequete() {}
...
FacesContext.getCurrentInstance().addMessage("errorMessage", facesMessage);
}
Finally, you should tell when to update this component by adding update attribute :
<p:commandButton ... update="errorMessage" />
Related
I am using JSF 2.2.20. In the xhtml page, there is one input text field and a file upload (advanced mode) . But my problem is, while listener is called for file-upload, the input text is coming as empty. How can I get the input text? Help me out.
xhtml code snippet:
<h:form id="formID" enctype="multipart/form-data" method="post">
<p:growl id="growlId" sticky="true" showDetail="true"><p:autoUpdate /></p:growl>
<p:outputPanel id="DocInfo">
<h:panelGrid id="DocGrid" columns="3" style="margin-bottom:10px" cellpadding="8">
<p:outputLabel for="upload_Doc_Name" value="Document Name :* " />
<p:inputText id="upload_Doc_Name" value="#{uploadDocManagedBean.uploadDocName}" style="font-size:8pt;width:230px" />
<p:outputLabel for="projectUploadDocId" value="Choose File :* " style="font-weight:bold; float:left" />
<p:fileUpload id="projectUploadDocId" value="#{uploadDocManagedBean.uploadedFile}" mode="advanced" dragDropSupport="true"
listener="#{uploadDocManagedBean.fileUploadListener}" />
<br/>
</h:panelGrid>
</p:outputPanel>
</h:form>
The managed bean code snippet:
#ManagedBean(name = "uploadDocManagedBean")
#ViewScoped
public class UploadDocManagedBean implements Serializable {
private static final long serialVersionUID = -1L;
private String uploadDocName;
private UploadedFile uploadedFile;
public String getUploadDocName() {
return uploadDocName;
}
public void setUploadDocName(String uploadDocName) {
this.uploadDocName = uploadDocName;
}
public UploadedFile getUploadedFile() {
return uploadedFile;
}
public void setUploadedFile(UploadedFile uploadedFile) {
this.uploadedFile = uploadedFile;
}
public void fileUploadListener(FileUploadEvent fileUploadEvent) {
try {
uploadedFile = fileUploadEvent.getFile();
String filename = uploadedFile.getFileName();
if (uploadDocName == null || uploadDocName.isEmpty()) {
String msg = "Document Name is empty.";
FacesContext.getCurrentInstance().addMessage("growlId",
new FacesMessage(FacesMessage.SEVERITY_ERROR, msg, msg));
return;
}
} catch (Exception e) {
e.printStackTrace();
}
}
In the managed bean, the uploadDocName is the coming as empty everytime, while this fileUploadListener() method is called.
What am I missing here?
You can define process attribute on fileUpload. To make it simple, try with process="#form", it should work ;) By default, only fileUpload client id e.g #this is sent to the server for processing
More details for fileUpload component, see here: https://primefaces.github.io/primefaces/11_0_0/#/components/fileupload
I am creating an image gallery with JSF and PrimeFaces. I am using ui:repeat with p:graphicImage inside to display a list of images retrieved from db. Every image has an on click p:dialog (with its respective id) defined also inside ui:repeat. In the p:dialog I am showing again the clicked image and there is also a h:form that has inside a p:inputText and a p:commandbutton to save the text of p:inputText to a String property of a bean. The problem is that only last image of the list showed by ui:repeat "sees" the bean and set the property. If in the dialog of last image showed by ui:repeat I write a comment and click the commandbutton it sets the String text of the bean, if I do the same for the other images the String text is null. Maybe it's a problem of bean visibility. I tried to use different scopes for the bean but it doesn't work anyway.
This is the JSF code:
<ui:repeat value="#{imageShowController.images}" var="img">
<h:outputLink value="javascript:void(0)"
onclick="PF('picDialog-#{img.id}').show();">
<p:graphicImage value="#{imageShowController.streamedContent}"
width="250" height="250" cache="false">
<f:param name="id" value="#{img.id}" />
</p:graphicImage>
</h:outputLink>
<p:dialog id="picDialog-#{img.id}" widgetVar="picDialog-#{img.id}"
width="500" height="500">
<p:graphicImage value="#{imageShowController.streamedContent}">
<f:param name="id" value="#{img.id}" />
</p:graphicImage>
<h:form>
<h:panelGrid columns="2" cellpadding="5">
<p:inputText value="#{imageShowController.txt}" />
<p:commandButton value="Submit comment"
action="#{imageShowController.saveComment()}">
<f:param name="id" value="#{img.id}" />
</p:commandButton>
</h:panelGrid>
</h:form>
</p:dialog>
</ui:repeat>
This is the bean (Java):
#ManagedBean
#RequestScoped
public class ImageShowController {
#Inject
private UserSessionBean userSession;
#Inject
private ImageDaoService imagedao;
#Inject
private CommentDaoService commentdao;
private List<Image> images;
private String text;
private String id;
#PostConstruct
public void init() throws SQLException {
images = new ArrayList<>();
images = imagedao.findImagesByUserId( userSession.getUserId() );
}
public void saveComment(){
FacesContext context = FacesContext.getCurrentInstance();
String id =
context.getExternalContext().getRequestParameterMap().get("id");
Comment comment = new Comment();
comment.setText(text);
comment.setDate(new Date());
comment.setImage(imagedao.findById(Long.valueOf(id)).get(0));
commentdao.addComment(comment);
}
public StreamedContent getStreamedContent() throws IOException {
FacesContext context = FacesContext.getCurrentInstance();
if (context.getCurrentPhaseId() == PhaseId.RENDER_RESPONSE) {
return new DefaultStreamedContent();
}
else {
id =
context.getExternalContext().getRequestParameterMap().get("id");
System.out.println("INDEX: "+id);
byte [] b = null;
for (int i = 0; i < images.size(); i++) {
if(images.get(i).getId() == Long.valueOf(id)){
b = images.get(i).getPicture();
break;
}
}
return new DefaultStreamedContent(new ByteArrayInputStream(b));
}
}
}
I solved using tag c:forEach of JSTL instead of ui:repeat. It works!!
I'm working with a web application with the following technologies
spring 4.3
JSF 2.2.14
PrimeFaces 6.1
Omnifaces 2.6.4
I need to validate an h:inputText, and I'm trying to use the javax.faces.validator.Validator interface.
All is working well but when the validation fail, I'm not able to retrieve the label of the field, that is stored in a p:outputLabel using the "for" attribute.
Facelets code
<p:outputLabel id="selectedAdvPriceOutputLabel" for="selectedAdvPrice" value="#{msg['prezzo']}"/>
<h:inputText id="selectedAdvPrice"
value="#{addAdvertisingController.advertisingBean.price}"
class="form-control"
converter="javax.faces.BigDecimal"
required="#{empty param[draftSave.clientId] and empty param[draftSaveXS.clientId]}"
requiredMessage="#{msg['prezzo']} #{msg['campoObbligatorio']}">
<f:validator binding="#{numberGreaterThanZeroJsfValidator}" />
</h:inputText>
Validator - validate method
public void validate(FacesContext context, UIComponent component, Object value) {
if (value != null) {
String v = value.toString();
if (StringUtils.isNotEmpty(v)) {
try {
BigDecimal bd = new BigDecimal(v);
if(bd.compareTo(BigDecimal.ZERO) <= 0){
// how to retrieve the field label???
FacesMessage msg = new FacesMessage("messageWithout label", "messageWithout label");
msg.setSeverity(FacesMessage.SEVERITY_ERROR);
throw new ValidatorException(msg, new IllegalArgumentException(exceptionMessage));
}
} catch (NumberFormatException e) {
FacesMessage msg = new FacesMessage("messageWithout label", "messageWithout label");
msg.setSeverity(FacesMessage.SEVERITY_ERROR);
throw new ValidatorException(msg, new IllegalArgumentException(exceptionMessage));
}
}
}
}
How can I retrieve the value attribute of the p:outputLabel linked to the h:inputText that is not passing the validation?
Thank you
According to Primefaces User's Guide --> 3.93 OutputLabel
Auto Label
OutputLabel sets its value as the label of the target component to be displayed in validation errors so the target component
does not need to define the label attribute again.
<h:outputLabel for="input" value="Field" />
<p:inputText id="input" value="#{bean.text}" label="Field"/>
can be rewritten as;
<p:outputLabel for="input" value="Field" />
<p:inputText id="input" value="#{bean.text}" />
It means, that OutputLabel simply sets the label attributte of a component to which the label is attached.
Just retrieve this attributte in the validator, for example in this way:
public void validate(FacesContext context, UIComponent component, Object value) {
Object labelObj = component.getAttributes().get("label");
String label = (labelObj!=null) ? labelObj.toString() : "Unknown label";
.....
.....
// how to retrieve the field label???
String message = String.format("%s : My conversion error message", label);
FacesMessage msg = new FacesMessage(message,message) ;
.....
.....
I've tested it and it works for both p:inputText and h:inputText components.
Hi, I've debugged the code and component.getAttributes().get("label")
is null
I've tested it again on JSF 2.2/Primefaces 6.1/Wildfy 10.x and it works.
Here is a simple demo project on GitHub link
index.xhtml
<!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:ui="http://java.sun.com/jsf/facelets"
xmlns:f="http://java.sun.com/jsf/core"
xmlns:h="http://java.sun.com/jsf/html"
xmlns:p="http://primefaces.org/ui">
<h:head></h:head>
<h:body>
<h:form>
<p:panel id="panel" header="Form" style="margin-bottom:10px;">
<p:messages id="messages" />
<h:panelGrid columns="2" cellpadding="5">
<p:outputLabel id="label1_id"
for="input1_id" value="This Is My label for h:input" />
<h:inputText id="input1_id" value="#{myBean.price1}"
required="true" >
<f:validator validatorId="MyValidator" />
</h:inputText>
<p:outputLabel id="label2_id"
for="input2_id" value="This Is My label for p:input" />
<p:inputText id="input2_id" value="#{myBean.price2}" required="true">
<f:validator validatorId="MyValidator" />
</p:inputText>
</h:panelGrid>
<p:commandButton update="panel" value="Submit" />
</p:panel>
</h:form>
</h:body>
</html>
bean
#Named
#SessionScoped
public class MyBean implements Serializable {
private static final long serialVersionUID = 5455916691447931918L;
private Integer price1;
private Integer price2;
public Integer getPrice2() {
return price2;
}
public void setPrice2(Integer price2) {
this.price2 = price2;
}
public Integer getPrice1() {
return price1;
}
public void setPrice1(Integer price1) {
this.price1 = price1;
}
}
Validator
#FacesValidator("MyValidator")
public class MyValidator implements Validator {
public void validate(FacesContext context, UIComponent component, Object value) {
Object labelObj = component.getAttributes().get("label");
String label = (labelObj!=null) ? labelObj.toString() : "Unknown label";
if (value != null) {
String v = value.toString();
if (null != v && !v.isEmpty()) {
try {
BigDecimal bd = new BigDecimal(v);
if (bd.compareTo(BigDecimal.ZERO) <= 0) {
// how to retrieve the field label???
String message = String.format("%s : Value must be greater than 0", label);
FacesMessage msg = new FacesMessage(message,message) ;
msg.setSeverity(FacesMessage.SEVERITY_ERROR);
throw new ValidatorException(msg, new IllegalArgumentException("Validator exception:" + message));
}
} catch (NumberFormatException e) {
String message = String.format("%s : Value must be a number", label);
FacesMessage msg = new FacesMessage(message,message);
msg.setSeverity(FacesMessage.SEVERITY_ERROR);
throw new ValidatorException(msg, new IllegalArgumentException("Validator exception:" + message));
}
}
}
}
}
And a result is:
Some things that may help or are common:
remove id from *:outputLabel as this is not needed
use validatorMessage="#{bundle.SOME_FIELD_VALIDATION_ERROR}" to have a localizable message, if your validator is throwing javax.faces.validator.ValidatorException (you can import this above your validator class, of course)
get rid of the code for the label-retrieval, see above validatorMessage field
<f:validator binding="#{someValidator}" /> seem to cause more problems, common way is: <f:validator validatorId="SomeFooValidator" /> within *:inputText (you have to make it non-self-closing)
and then annotate your validator class with #FacesValidator ("SomeFooValidator") (javax.faces.validator.FacesValidator)
Are you using JSF2.2?
Prerequisites:
- JSF 2.1
- Primefaces 5.2
- Glassfish 3.1
Story:
I've created a p:dialog used for displaying FacesMessages on a p:messages element. This dialog is needed, because the user has to commit specific FacesMessages with an "OK"-Button before proceeding.
Dialog:
<p:outputPanel id="modalMessage">
<p:dialog id="dlgMessageDialog" dynamic="true" style="z-index: 100"
closable="false" widgetVar="wigVarMessageDialog" modal="true"
appendTo="#(body)">
<f:facet name="header">
<h:outputText id="messageDialogHeader"
value="#{messageDialogBean.header}" />
</f:facet>
<p:outputPanel id="modalMessagePanel">
<h:form id="messageForm" enctype="multipart/form-data">
<p:messages id="messages" escape="false" closable="false"
showDetail="true" autoUpdate="true"
for="#{messageDialogBean.messageDialogId}"></p:messages>
<p:spacer height="20px"></p:spacer>
<p:commandButton value="#{msg.btnOk}"
oncomplete="PF('wigVarMessageDialog').hide()" />
</h:form>
</p:outputPanel>
</p:dialog>
</p:outputPanel>
Bean:
#Named("messageDialogBean")
#SessionScoped
public class MessageDialogBean implements Serializable {
private static final long serialVersionUID = 1L;
private final String messageDialogId = "messageDialogId";
private FacesMessage message = new FacesMessage();
private String header = "test";
public void showMessage(final String pHeader, final FacesMessage pMessage) {
if (pMessage != null) {
setHeader(pHeader);
this.message = pMessage;
show();
}
}
public void showWarn(final String pHeader, final String pSummary, final String pDetail) {
setHeader(pHeader);
this.message = new FacesMessage(FacesMessage.SEVERITY_WARN, pSummary, pDetail);
show();
}
public void showInfo(final String pHeader, final String pSummary, final String pDetail) {
setHeader(pHeader);
this.message = new FacesMessage(FacesMessage.SEVERITY_INFO, pSummary, pDetail);
show();
}
public void showError(final String pHeader, final String pSummary, final String pDetail) {
setHeader(pHeader);
this.message = new FacesMessage(FacesMessage.SEVERITY_ERROR, pSummary, pDetail);
show();
}
public void updateDialog() {
RequestContext context = RequestContext.getCurrentInstance();
context.update("mainForm:messageDialogHeader");
}
private void show() {
updateDialog();
RequestContext context = RequestContext.getCurrentInstance();
context.execute("PF('wigVarMessageDialog').show();");
FacesContext.getCurrentInstance().addMessage(this.messageDialogId, this.message);
}
public String getMessageDialogId() {
return this.messageDialogId;
}
public void setHeader(final String pHeader) {
this.header = pHeader;
}
public String getHeader() {
return this.header;
}
public FacesMessage getLastMessage() {
return this.message;
}
}
One of the messages which have to be commited:
this.messageDialogBean.showInfo("Title", "Summary", "Detail");
Problem:
The p:messages element of the dialog does not show the message when the dialog is opened the first time. After opening and hiding it once it shows all further FacesMessages just fine.
Question:
So far i am useing opening and closeing the dialog once when the interface is initialized as a workarround. Does annyone know what causes this problem in the first place and also how to solve it properly?
Thanks for answers
First of all it is not allowed to put a form inside of another, as stated in W3C XHTML specification, "form must not contain other form elements." visit: https://www.w3.org/TR/xhtml1/#prohibitions.
So your dialog should not be inside of the main form, you have to sperate the dialog from the form, your code sould be orginsed like this :
<form id="mainForm" >
<!--your main page-->
</form>
<p:dialog id="dlgMessageDialog" >
<h:form id="messageForm" enctype="multipart/form-data">
<f:facet name="header">
<h:outputText id="messageDialogHeader"
value="#{messageDialogBean.header}" />
</f:facet>
<p:messages id="messages" escape="false" closable="false"
showDetail="true" autoUpdate="true"
for="#{messageDialogBean.messageDialogId}"></p:messages>
<p:spacer height="20px"></p:spacer>
<p:commandButton value="#{msg.btnOk}"
oncomplete="PF('wigVarMessageDialog').hide()" />
</h:form>
</p:dialog>
Another thing, you have to update the whole dialog, so when the dialog is opened the messges is automaticly updated :
context.update("dlgMessageDialog");
I have a jsf page that has 2 parts: a table displaying a list of records and a dialog to add a new record. I added some validation features but I can't get them to work properly.
I need it to:
1) Validation error not appear the first time dialog shows up
2) If any validation error happens, keep it open and show error messages.
3) If no validation error and back-end executed successfully, update the table.
This is what I have:
<h:body>
<h:form id="form01">
<p:dataTable id="tbl1" value="#{welcomeController.teams}" var="team" >
<p:column headerText="Id">
<h:outputText value="#{team.seq}" />
</p:column>
<p:column headerText="Name">
<h:outputText value="#{team.name}" />
</p:column>
</p:dataTable>
<p:dialog id="teamDialog" closable="false" visible="#{welcomeController.addMode}"
widgetVar="teamDialog_w" modal="true" resizable="false" draggable="true"
header="New Team Detail">
<p:messages />
<p:panelGrid columns="2">
<h:outputText value="Name" />
<p:inputText id="name" value="#{welcomeController.newTeam.name}" />
</p:panelGrid>
<p:commandButton value="Submit" ajax="true" actionListener="#{welcomeController.addNewTeam}"
update=":form01"oncomplete="teamDialog_w.hide(); console.log(args);" />
</p:dialog>
<p:commandButton value="ADD" actionListener="#{welcomeController.startAdd}"
oncomplete="teamDialog_w.show(); console.log(args);" update="teamDialog" />
</h:form>
The bean:
#Named
#ConversationScoped
public class WelcomeController implements Serializable {
private final Logger logger = LoggerFactory.getLogger(this.getClass());
private static final long serialVersionUID = 1L;
private List<TeamDto> teams;
#Inject SessionManager sessionMan;
#Inject DatabaseUtil dbCache;
#Inject TeamService teamService;
#Inject Conversation conversation;
private TeamDto newTeam = new TeamDto();
private boolean addMode = false;
public List<TeamDto> getTeams() throws IOException {
if (teams == null || teams.size() == 0) {
teams = teamService.getAll();
}
return teams;
}
public void setTeams(List<TeamDto> teams) {
this.teams = teams;
}
public void reload() {
conversationBegin();
}
public void conversationBegin() {
if (conversation.isTransient()) {
conversation.begin();
}
}
public void conversationEnd() {
if(!conversation.isTransient()){
conversation.end();
}
}
public void startAdd() {
reload();
newTeam = new TeamDto();
addMode = true;
}
public TeamDto getNewTeam() {
return newTeam;
}
public void setNewTeam(TeamDto newTeam) {
this.newTeam = newTeam;
}
public void addNewTeam() throws IOException, ValidatorException {
if (newTeam.getName().isEmpty()) {
sessionMan.addGlobalMessageFatal("INVALID INFO", null);
return;
}
teamService.addTeam(newTeam);
teams.add(newTeam);
newTeam = new TeamDto();
addMode = false;
}
public boolean isAddMode() {
return addMode;
}
public void setAddMode(boolean addMode) {
this.addMode = addMode;
}
}
I have 2 problems here:
1) After I submit an empty string, I expect the dialog to still open (because addMode is true) but it's not. Why is it?
2) If I put the "ADD" button like this:
<p:commandButton value="ADD" actionListener="#{welcomeController.startAdd}" oncomplete="teamDialog_w.show(); console.log(args);" >
<f:ajax render="teamDialog" />
</p:commandButton>
at least when I open the dialog again, I can see the error message. But in my code, I can't see the error message. Why is it so? Aren't they equivalent?
Is there anything wrong with my understanding?
Please help. Thank you very much.
Dialogs should operate with their own form in JSF, this is crucial.
To prevent your dialog from closing on validation you can use in Primefaces :
if (args &&
!args.validationFailed){PF('eventDialog').hide();}
like this:
<p:commandButton value="ADD"
actionListener="#{welcomeController.startAdd()}"
oncomplete="if (args && !args.validationFailed){PF('teamDialog').hide();}"
update="your_dialog_formID:messages, other_updated_IDs" />
here
if (args && !args.validationFailed){PF('teamDialog').hide();}
you can obvoiusly add else clause and do #3 "If no validation error and back-end executed successfully, update the table."
here BalusC gives great explenation why:Keep p:dialog open when a validation error occurs after submit