How to assign value to global variable in bean through ajax - ajax

I need your help in assigning the entered value in an inputText to a global variable that can be used in multiple methods in a bean. The JSF page has the code:
<p:dialog id="Dialog1" header="Dialog1" widgetVar="Dialog1">
<p:inputText id="refNo2" value="#{Bean1.refNo}">
<p:ajax event="keyup" update="ref2" />
</p:inputText>
<h:outputText id="ref2" value="#{Bean1.refNo}"/>
<p:commandButton value="Download" ajax="false" actionListener="#{Bean1.PDFExport}" />
</p:dialog>
With the above code anything that is entered in the inputText, it will be shown in the outputText. And the java code for refNo in Bean1 is:
#SessionScoped
private String refNo = "";
public void setRefNo(String refNo) {
this.refNo = refNo;
}
public String getRefNo() {
return refNo;
}
However, When I am calling PDFExport method in the actionListener, the value of the refNo is blank and therefore I can't write any query because the value of refNo is not passed:
public void PDFExport() {
System.out.println("Reference No. is"+refNo);
}
An example is that if the entered value in the inputText is 99, the outputText will show 99, however on clicking on the commandButton, the refNo value is blank.

Related

JSF reset conditionally rendered input field

EDIT
If have found the solution, but I need help understanding it. Questions are listed below
Whenever I try to reset the value of a conditionally rendered field, it reverts to a previously entered value instead of a null value.
The following is an explanation of the unexpected behavior:
checkbox is true --> textfield is rendered
enter 'test' into textfield
uncheck checkbox --> texfield is not rendered
click reset button --> checkbox value = true && textfield value = null
expected --> inputtextfield with null value
actual --> inputtextfield with 'test' value
Simplified example
Form
<h:form>
<p:selectBooleanCheckbox value="#{testController.inputTextRendered}">
<p:ajax process="#form" update="#form"/>
</p:selectBooleanCheckbox>
<h:inputText value="#{testController.inputText}" rendered="#{testController.inputTextRendered}"/>
<p:commandButton process="#this" update="#form" action="#{testController.reset}"/>
</h:form>
Controller
#Named
#ViewScoped
public class TestController implements Serializable {
private boolean inputTextRendered = true;
private String inputText;
public void reset() {
setInputTextRendered(true);
setInputText(null);
}
public boolean isInputTextRendered() {
return inputTextRendered;
}
public void setInputTextRendered(boolean inputTextRendered) {
this.inputTextRendered = inputTextRendered;
}
public String getInputText() {
return inputText;
}
public void setInputText(String inputText) {
this.inputText = inputText;
}
}
side notes
it's the omnifaces #ViewScoped annotation
the process #form on the checkbox is necessary, because deselecting the checkbox should not reset the value of the textfield (only the button should reset it)
Solution
This code works
<h:form id="testForm">
<p:selectBooleanCheckbox value="#{testController.inputTextRendered}">
<p:ajax process="#form" update="#form"/>
</p:selectBooleanCheckbox>
<h:inputText value="#{testController.inputText}" rendered="#{testController.inputTextRendered}"/>
<p:commandButton process="#this" update="#form" actionListener="#{testController.reset}">
<p:resetInput target="#form"/>
</p:commandButton>
</h:form>
But this raises some questions:
Why do I need to add a p:resetInput when no validation errors even occur?
Why do I need to use the actionListener attribute instead of the action attribute?

Render a component only when validation success

In JSF 2.X, can I render a component only when the validation success?
In my application I have many fields that must be filled. These data can be imported from a WebService through a search key.
When the user enter a valid search key the system searches the other fields and render them with the new values. But when the user enter a nonexistent key (or any other validation error) the server generates a validation error but still renders the fields, thus losing any data that there were filled.
What I need is that the user can perform the query and that if the query does not return results, this does not affect any data that he has already entered.
Below is a code example. Thus, if the user has filled in the fields inside updateThisOnSuccess and just after making an attempt to query without success, the value that is filled in is not lost.
<h:inputText value="#{controller.searchWebService}" >
<f:ajax execute="#this" render="updateThisOnSuccess messages" />
</h:inputText>
<h:panelGroup id="updateThisOnSuccess">
<h:inputText value="#{controller.field}" />
<!-- other fields -->
</h:panelGroup>
Submit the field values to run the search also does not seem an option as this will cause need to validate the fields inside updateThisOnSuccess.
Note: I saw the answer given by #BalusC to a similar question, but this is different from what I'm wondering why, in that case, foo-holder is always rendered and foo is conditioning. It's not my case, since this approach would make the controls do not appear when the validation fails.
Try this
<h:panelGroup id="updateThisOnSuccess">
<ui:fragment rendered="#{not facesContext.validationFailed}">
<h:inputText value="#{controller.field}" />
<!-- other fields -->
</ui:fragment>
</h:panelGroup>
Plaase try this. The requirements are that you must implement model validations with Bean Validation and the search field must implement JSF validation if required.
If you write "123456" then data is returned, else nothing is returned and a message is printed.
The backing bean:
#Named
#ViewScoped
public class yourBean implements Serializable{
private static final long serialVersionUID = 1L;
#Size(min=2)
private String field01;
private String searchWebService;
public void saveF(){
System.out.println("save");
}
public void searchWebServiceF(){
Boolean successWS = ("123456").equals(this.searchWebService);
if(successWS){
this.setField01("WS data");
}else{
FacesContext.getCurrentInstance().
addMessage(null, new FacesMessage(FacesMessage.SEVERITY_ERROR, "WS fails", ""));
}
}
public String getSearchWebService() {
return searchWebService;
}
public void setSearchWebService(String searchWebService) {
this.searchWebService = searchWebService;
}
public String getField01() {
return field01;
}
public void setField01(String field01) {
this.field01 = field01;
}
}
In your page:
<h:form id="form01">
<h:messages id="message"/>
<h:inputText id="wsid" value="#{pruebasBorradorBean.searchWebService}">
<f:validateLength maximum="6"/>
<f:ajax execute="#form" render="#form" listener="#{pruebasBorradorBean.searchWebServiceF()}" />
</h:inputText>
<h:panelGroup id="thedata">
<h:inputText value="#{pruebasBorradorBean.field01}">
<f:validateBean disabled="#{param['javax.faces.source']!='form01:save'}"/>
</h:inputText>
<!-- other fields -->
</h:panelGroup>
<h:commandButton id="save" value="submit">
<f:ajax render="thedata message" execute="#this thedata" listener="#{pruebasBorradorBean.saveF()}"/>
</h:commandButton>
</h:form>
You can change the components that will be processed in render phase changing the Collection at getRenderIds() of PartialViewContext. According to documentation this Collection is mutable.
FacesContext.getCurrentInstance().getPartialViewContext().getRenderIds().remove("formName:updateThisOnSuccess");
To test this solution, I used this controller:
#Named
#ViewScoped
public class Controller implements Serializable {
private static final long serialVersionUID = 1L;
private final static List<String> LIST_VALID_WEB_SERVICE_SEARCHS =
Arrays.asList(new String[] {"foo", "bar"});
private String webServiceParameter;
private Integer field01;
public void searchWebService() {
if (LIST_VALID_WEB_SERVICE_SEARCHS.contains(getWebServiceParameter())) {
setField01(123);
} else {
FacesContext facesContext = FacesContext.getCurrentInstance();
facesContext.getPartialViewContext().getRenderIds().remove("formFields");
FacesMessage facesMessage = new FacesMessage("Search not found in WebService.");
facesMessage.setSeverity(FacesMessage.SEVERITY_ERROR);
facesContext.addMessage("formName:searchWebService", facesMessage);
}
}
public void submit() {
System.out.println("submitted");
}
// Getters and Setters
}
And used this view:
<h:form id="formSearch">
<h:inputText id="webServiceParameter" value="#{controller.webServiceParameter}">
<f:ajax execute="#this" render="formFields messages" listener="#{controller.searchWebService}" />
</h:inputText><br />
</h:form>
<h:form id="formFields">
<h:inputText id="field01" value="#{controller.field01}" required="true">
<f:validateLongRange minimum="2" maximum="345" />
</h:inputText><br />
<!-- other fields -->
<h:commandButton value="submit" action="#{controller.submit}">
<f:ajax render="#form messages" execute="#form" />
</h:commandButton>
</h:form>
<h:messages id="messages" />
You can do something like that:
<f:ajax execute="#this" render="#{controller.success} message"/>
where success is a String attribute that will be empty if the WS fails and will be "updateThisOnSuccess" if not .
Or you could get rid of the JSF validation mechanism for informing the user the WS has failed. Think of it, it is not really a validation of the Model. You could draw an icon beside the WS Id field in red color or something similar using a boolean flag attribute in the backing bean.

Validate a number value without custom validator in JSF

I have a JSF form. I want a message to be displayed, when a user entered 0 in qty field and clicked on the Add To Card button.
Here is the JSF form:
<h:form>
<h:inputText id="qtyField" value="#{booksBean.qty}">
<!--What kind of validation should i use here?-->
<f:ajax event="blur" render="qtyMsg"/>
</h:inputText>
<h:message id="qtyMsg" for="qtyField"/>
<h:commandButton value="Add To Card"
action="#{booksBean.orderBook()}"
rendered="#{booksBean.qty>0}">
<f:ajax execute="#form" rendered="#form"/>
</h:commandButton>
</h:form>
Do I need a custom validator class just to simply compare a number value with a zero?
Like this:
#FacesValidator("myValidator")
public class MyValidator implements Validator {
#Override
public void validate(FacesContext context, UIComponent component, Object value) {
if (intValue== 0 || intValue <0) {
throw new ValidatorException(new FacesMessage(...));
}
//...
}
Is there any shorter way without creating a custom validator class?
You can use f:validateLongRange for this.
<h:inputText value="#{backingBean.input1}">
<f:validateLongRange minimum="1" />
</h:inputText>
Checks whether the local value of a component is within a certain
range. The value must be any numeric type or String that can be
converted to a long.

InputText with validation does not work properly inside ui:repeat JSF 2.2.6

I have the following xhtml, validator, and managedBean:
<h:form id="form">
<ui:repeat var="item" value="#{myBean.usersEmail}" varStatus="status">
<p:inputText id="userEmail" value="#{item.email}">
<f:validator validatorId="MyValidator"/>
</p:inputText>
<p:commandButton value="++++" update=":form" action="#{myBean.addEmail()}" />
</ui:repeat>
</h:form>
#FacesValidator("MyValidator")
public class ValidationClass extends Validator {
#Override
public void validate(FacesContext ctx, UIComponent component, Object value) throws ValidatorException {
String email = value.toString();
EmailValidator validator = EmailValidator.getInstance();
if(StringUtils.isNotBlank(email) && !validator.isValid(email)) {
FacesMessage message = new FacesMessage();
message.setSeverity(FacesMessage.SEVERITY_ERROR);
message.setSummary("Email is not valid.");
message.setDetail("Email is not valid.");
ctx.addMessage("userEmail", message);
throw new ValidatorException(message);
}
}
}
#ManagedBean
public class MyBean{
#Getter
#Setter
List<UserEmail> usersEmail = new ArrayList<UserEmail>();
public void addEmail(){
usersEmail.add(new UserEmail());
}
}
public class UserEmail{
#Getter
#Setter
String email = "";
}
The email addition works fines until the first validation fail.
When this happens, all inputText components show the same values.
For example, first I add "user1#gmail.com", this works ok.
Then I add "user2#gmail.com", this also works ok.
Then I change "user1#gmail.com" to "", this throws a validation exception, which is shown on the screen, and everything is still ok.
But then I correct the "" with "user3#gmail.com" and submit, this time all inputText start showing "user2#gmail.com", even when I add a new InputText, which also shows "user2#gmail.com".
It seems that when the validation fail, all components inside ui:repeat get bound to the value of the last item. Any thoughts?
I changed my implementation to use the c:forEach tag from JSTL and now it's working fine, even on Mojarra 2.2.6, here it's what I did:
<c:forEach var="item" items="#{myBean.usersEmail}" varStatus="status">
<p:inputText id="id${status.index}" value="${item.email}" validator="MyValidator" />
<p:message for="id${status.index}" />
<p:commandButton value="+" update=":form" action="#{myBean.addEmail()}" />
</c:forEach>

JSF2 - what scope for f:ajax elements?

I have this form:
<h:form>
<h:outputText value="Tag:" />
<h:inputText value="#{entryRecorder.tag}">
<f:ajax render="category" />
</h:inputText>
<h:outputText value="Category:" />
<h:inputText value="#{entryRecorder.category}" id="category" />
</h:form>
What I'm trying to achieve: When you type in the "tag" field, the entryRecorder.tag field is updated with what was typed. By some logic upon this action the bean also updates its category field. This change should be reflected in the form.
Questions:
What scope shall I use for EntryRecorder? Request may not be satisfactory for multiple AJAX requests, while session will not work with multiple browser windows per one session.
How can I register my updateCategory() action in EntryRecorder so that it is triggered when the bean is updated?
Answering point 2:
<h:inputText styleClass="id_tag" value="#{entryRecorder.tag}"
valueChangeListener="#{entryRecorder.tagUpdated}">
<f:ajax render="category" event="blur" />
</h:inputText>
Bean:
#ManagedBean
#ViewScoped
public class EntryRecorder {
private String tag;
private String category;
#EJB
private ExpenseService expenseService;
public void tagUpdated(ValueChangeEvent e) {
String value = (String) e.getNewValue();
setCategory(expenseService.getCategory(value));
}
}
Number 1, anybody?
To point 1, I'll use Request since there is no need to use View and Session is, as you well pointed, completely unnecessary.
For point 2, since you are using <f:ajax/> I suggest making full use of it. Here is my proposal:
xhtml:
<h:form>
<h:outputText value="Tag:" />
<h:inputText value="#{entryRecorder.tag}">
<f:ajax render="category" event="valueChange"/>
</h:inputText>
<h:outputText value="Category:" />
<h:inputText value="#{entryRecorder.category}" id="category" />
</h:form>
Note the use of valueChange event instead of blur (not that blur doesn't work but I find valueChange more 'proper' for a value holder component).
bean:
#ManagedBean
#RequestScoped
public class EntryRecorder {
private String tag;
private String category;
public String getCategory() {
return category;
}
public String getTag() {
return tag;
}
public void setCategory(String category) {
this.category = category;
}
public void setTag(String tag) {
this.tag = tag;
tagUpdated();
}
private void tagUpdated() {
category = tag;
}
}
Unless you really want the tagUpdated method executed only when tag is updated through the view, my proposal looks more clear. You don't have to deal with the events (nor casting) and the tagUpdated method can be private hiding it's functionality from possible misuses.

Resources