I am very new to JSF (v2.0) and I am attempting to learn it at places like netbeans.org and coreservlets.com. I am working on a very simple "add/subtract/multiply/divide" Java webapp and I have run into a problem. When I first started out, the application was enter two numbers and hit a '+' key and they would be automatically added together. Now that I have added more complexity I am having trouble getting the operation to the managed bean. This is what I had when it was just "add":
<h:inputText styleClass="display" id="number01" size="4" maxlength="3" value="#{Calculator.number01}" />
<h:inputText styleClass="display" id="number02" size="4" maxlength="3" value="#{Calculator.number02}" />
<h:commandButton id="add" action="answer" value="+" />
For the "answer" page, I display the answer like this:
<h:outputText value="#{Calculator.answer}" />
I had the proper getters and setters in the Calculator.java managed bean and the operation worked perfectly.
Now I have added the other three operations and I am having trouble visualizing how to get the operation parameter to the bean so that I can switch around it. I tried this:
<h:commandButton id="operation" action="answer" value="+" />
<h:commandButton id="operation" action="answer" value="-" />
<h:commandButton id="operation" action="answer" value="*" />
<h:commandButton id="operation" action="answer" value="/" />
However, Glassfish complained that I have already used "operation" once and I am trying to use it four times here.
Any adivce/tips on how to get multiple operations to the managed bean so that it can preform the desired operation?
Thank you for taking the time to read.
The component id should indeed be unique. This is implicitly required by the HTML specification. You know, all JSF does is just generating the appropriate HTML/CSS/JS code. Give them all a different id or just leave it away, it has no additional value in this specific situation (unless you'd like to hook some CSS/JS on it).
To achieve your functional requirement, you may find f:setPropertyActionListener useful.
<h:commandButton action="answer" value="+">
<f:setPropertyActionListener target="#{calculator.operation}" value="+" />
</h:commandButton>
<h:commandButton action="answer" value="-">
<f:setPropertyActionListener target="#{calculator.operation}" value="-" />
</h:commandButton>
<h:commandButton action="answer" value="*">
<f:setPropertyActionListener target="#{calculator.operation}" value="*" />
</h:commandButton>
<h:commandButton action="answer" value="/">
<f:setPropertyActionListener target="#{calculator.operation}" value="/" />
</h:commandButton>
And have a property operation in your calculator managed bean:
private String operation; // +setter.
You can access it in the getAnswer() method and handle accordingly.
Alternatively, let the buttons each point to a different bean action but which returns all "answer":
<h:commandButton action="#{calculator.add}" value="+" />
<h:commandButton action="#{calculator.substract}" value="-" />
<h:commandButton action="#{calculator.multiply}" value="*" />
<h:commandButton action="#{calculator.divide}" value="/" />
with the following methods in your calculator managed bean:
public String add() {
answer = number1 + number2;
return "answer";
}
public String substract() {
answer = number1 - number2;
return "answer";
}
// etc...
and just let getAnswer() return answer and do nothing else there. That's a more clean separation of responsibilities.
Related
I am using Omnifaces <o:validateBean /> to use JSR303 bean validation with a class level constraint.
The whole thing works quite good. The validation message is displayed in a Primefaces <p:messages /> component. Now I wanted to know whether it is possible to narrow the error message to a more precise component (i. e. a <p:message /> tag on a specific element)? In the example below I want to direct the error message to the <p:message /> component with id="id_msg_anniversary" (or if that is possible, to both id="id_msg_anniversary" and id="id_msg_wedding").
One of my intention is to validate everything with bean validation and not to use <o:validateOrder /> or <o:validateMultiple />.
#DayIsBeforeAnniversary
#Entity
public class Person implements Serializable
{
#Temporal(TemporalType.DATE)
private Date weddingDay;
#Temporal(TemporalType.DATE)
private Date silverWeddingAnniversary;
...
}
<p:messages id="id_messages" />
<h:outputLabel value="Wedding Day" />
<p:message id="id_msg_wedding" display="icon" for="id_wedding" />
<p:calendar
id="id_wedding"
value="#{personController.person.weddingDay}"> <br />
<h:outputLabel value="Silver Wedding Anniversary" />
<p:message id="id_msg_anniversary" display="icon" for="id_anniversary" />
<p:calendar
id="id_anniversary"
value="#{personController.person.silverWeddingAnniversary}" /> <br/>
<p:commandButton
value="test"
action="#{personController.navigate()}"
update="#all"/>
<o:validateBean value="#{personController.person}" />
public class DayIsBeforeAnniversaryValidator implements ConstraintValidator<DayIsBeforeAnniversary, Person>
{
#Override
public boolean isValid(Person person, ConstraintValidatorContext context)
{
return person == null
|| person.getWeddingDay() == null
|| person.getSilverWeddingAnniversary() == null
|| person.getWeddingDay().before(person.getSilverWeddingAnniversary());
}
...
}
public #interface DayIsBeforeAnniversary { ... }
For clarification I could attach more code.
The <o:validateBean> associates its message with the <h:form>. So, all you need to do is to make sure you have a <p:message for="formId"> at the desired place. Do note that you can have multiple of them. Below is a kickoff example.
<h:form id="formId">
<p:inputText id="foo" ... />
<p:message for="foo" />
<p:message for="formId" />
...
<p:inputText id="bar" ... />
<p:message for="bar" />
<p:message for="formId" />
...
<o:validateBean ... />
</h:form>
I however do agree this is not the most elegant solution, surely not when compared with members of ValidateMultipleFields family which has an useful showMessageFor attribute for the purpose. It's only unfortunately technically pretty convoluted to implement it on <o:validateBean> too as there's technically no direct relationship between BV constraint violation errors and JSF input fields, so it has to be manually inspected based on bean properties and JSF component tree, which is not exactly an oneliner work.
I created a very simple example based on my project in order to illustrate my doubt. Just a way to register a person with a list of telephone numbers.
MainController.java
private String name;
private List<Phone> phoneList;
// Getters and Setters
#PostConstruct
private void init() {
phoneList = new ArrayList<>();
}
public static class Phone implements Serializable {
private String number;
// Getters and Setters
#Override
public String toString() {
return number != null ? number : "null";
}
}
public void add() {
phoneList.add(new Phone());
}
public void save() {
System.out.println("Name: " + name + "; " + phoneList.toString());
}
index.xhtml
<h:form>
<h:inputText value="#{mainController.name}" required="true" />
<ui:repeat var="phone" value="#{mainController.phoneList}" varStatus="status">
<h:inputText value="#{phone.number}" required="true" />
</ui:repeat>
<h:commandButton action="#{mainController.add()}" value="Add Phone" immediate="true" />
<h:commandButton action="#{mainController.save()}" value="Save" />
</h:form>
In my example, note that all phone fields that are added MUST be filled in (required = true).
The problem is: when I type name and click add (to add a phone) the value of the field is maintained. But when I type a first phone and click add, the phone's value is not maintained. This occurs for all fields within the component ui:repeat.
Is there a way to preserve the input values within a after an immediate request, as with the name field?
Extra note: Other strange behavior I noticed is when add at least two phone fields, let the first blank and fills the second, and saves the form. After a failed validation (due to phone blank), click add will make all fields are filled with the value of the second phone.
Wildfly 9.0.2, JSF Api (Jboss) 2.2.12
Thanks to #BalusC comment. The OmniFaces library has two taghandlers that can be used in this case. In both cases input values will be preserved in case of validation failure. Note that h:commandButton should be with <h:commandButton immediate="false" />.
ignoreValidationFailed
In this case all validation failures will be ignored (including converter failures). Note that the h:form have to be changed to o:form. Also, the failures messages will still be displayed, which can be solved putting a proper condition in the rendered attribute. The files will look like this:
index.xhtml
<o:form>
<h:inputText value="#{mainController.name}" required="true" />
<ui:repeat var="phone" value="#{mainController.phoneList}" varStatus="status">
<h:inputText value="#{phone.number}" required="true" />
</ui:repeat>
<h:commandButton action="#{mainController.add()}" value="Add Phone">
<o:ignoreValidationFailed />
</h:commandButton>
<h:commandButton action="#{mainController.save()}" value="Save" />
</o:form>
<h:messages rendered="#{facesContext.validationFailed}" />
skipValidators
In this case only the validation failures will be ignored (the converters will still run). The failures messages will not be displayed, except for the converters. Note that this taghandler is only available since the 2.3 version. The files will look like this:
index.xhtml
<h:form>
<h:inputText value="#{mainController.name}" required="true" />
<ui:repeat var="phone" value="#{mainController.phoneList}" varStatus="status">
<h:inputText value="#{phone.number}" required="true" />
</ui:repeat>
<h:commandButton action="#{mainController.add()}" value="Add Phone">
<o:skipValidators />
</h:commandButton>
<h:commandButton action="#{mainController.save()}" value="Save" />
</h:form>
The solution that I use to this problem is to create an external field to the loop, which stores a JSON containing the values that should be saved. This field, to be outside the loop, properly saves values after each try and restore the missing values when necessary. I use two functions JavaScript and JQuery library.
So the files would look like this:
index.xhtml
<h:outputScript library="jquery" name="jquery.min.js" />
<h:outputScript library="all" name="all.js" />
<h:form>
<h:inputText value="#{mainController.name}" required="true" />
<ui:repeat var="phone" value="#{mainController.phoneList}" varStatus="status">
<h:inputText styleClass="savePhoneNumber" value="#{phone.number}" required="true" onchange="saveUiRepeatInput('#{allPhoneNumber.clientId}', 'savePhoneNumber')" />
</ui:repeat>
<h:inputHidden id="allPhoneNumber" binding="#{allPhoneNumber}" />
<h:outputScript>loadUiRepeatInput('#{allPhoneNumber.clientId}', 'savePhoneNumber')</h:outputScript>
<h:commandButton action="#{mainController.add()}" value="Add Phone" immediate="true" />
<h:commandButton action="#{mainController.save()}" value="Save" />
</h:form>
all.js
function saveUiRepeatInput(inputAll, inputClass) {
document.getElementById(inputAll).value = JSON.stringify($('.' + inputClass).map(function() { return this.value; }).get());
}
function loadUiRepeatInput(inputAll, inputClass) {
var jsonAll = document.getElementById(inputAll).value;
if (jsonAll) {
var array = JSON.parse(jsonAll);
$('.' + inputClass).each(function(i) { if (i < array.length) this.value = array[i]; });
}
}
Although work perfectly (including via ajax, with some minor changes), it looks like a hack, not an ideal solution. So if anyone can help with any solution strictly based on JSF, I will be grateful. Thanks.
I am using Primefaces 3.1.1. and very new to JSf in general.
I have two Calendar input fields on my form as such:
<p:calendar widgetVar="widgetFromDate" id="ID1" value="#{Bean.selected.From}" pattern="dd.MM.yyyy" mode="popup" showOn="button"> </p:calendar>
<p:calendar widgetVar="widgetFromTime" id="ID2" value="#{Bean.selected.Till}" pattern="HH:mm" timeOnly="true" mode="popup" showOn="button"> </p:calendar>
I have a third field which concatenates and shows the above two values on the click of h:commandButton.
For example:
The button:
<h:commandButton value="Speichern" onclick="????"></h:commandButton>
I am not really sure how one accomplishes that. Could there be a possibility to use some ajax events?
Any pointers would be greatly appreciated.
-BR
Just basically so:
<p:calendar ... value="#{bean.date1}" />
<p:calendar ... value="#{bean.date2}" />
<p:commandButton value="submit" action="#{bean.submit}" update="result" />
<h:outputText id="result" value="#{bean.date3}" />
with
public void submit() {
date3 = mergeSomehow(date1, date2);
}
Or if you insist in using standard JSF command button, this has the same effect:
<h:commandButton value="submit" action="#{bean.submit}">
<f:ajax execute="#form" render="result" />
</h:commandButton>
Implementation detail of merging is up to you and not in any way related to JSF/PrimeFaces. Just ask a basic java question if you stucks.
The onclick attribtue is at least insuitable for this as it provides in this particular case merely a hook to execute some JavaScript function before the form is being submitted. You're not interested in this hook.
One of the most common approaches to change locale in JSF+Seam - with <h:selectOneMenu>:
<h:form action="#{localeSelector.select}" rendered="false">
<h:selectOneMenu value="#{localeSelector.language}" onchange="submit()">
<f:selectItem itemLabel="English" itemValue="en" />
<f:selectItem itemLabel="Francais" itemValue="fr" />
</h:selectOneMenu>
</h:form>
I want to implement locale changes with buttons. So, the question is - how to pass the parameter (en, fr, etc.) to update the bean with <h:commandButton>? Maybe <h:inputHidden> would help?
Either pass as method argument (only if your environment supports EL 2.2),
<h:commandButton value="English" action="#{localeSelector.change('en')}" />
<h:commandButton value="Deutsch" action="#{localeSelector.change('de')}" />
<h:commandButton value="Français" action="#{localeSelector.change('fr')}" />
with
public void change(String language) {
locale = new Locale(language);
// ...
}
Or use <f:setPropertyActionListener>
<h:commandButton value="English" action="#{localeSelector.change}">
<f:setPropertyActionListener target="#{localeSelector.language}" value="en" />
</h:commandButton>
<h:commandButton value="Deutsch" action="#{localeSelector.change}">
<f:setPropertyActionListener target="#{localeSelector.language}" value="de" />
</h:commandButton>
<h:commandButton value="Français" action="#{localeSelector.change}">
<f:setPropertyActionListener target="#{localeSelector.language}" value="fr" />
</h:commandButton>
with
private String language;
public void change() {
locale = new Locale(language);
// ...
}
Or use <f:param>
<h:commandButton value="English" action="#{localeSelector.change}">
<f:param name="language" value="en" />
</h:commandButton>
<h:commandButton value="Deutsch" action="#{localeSelector.change}">
<f:param name="language" value="de" />
</h:commandButton>
<h:commandButton value="Français" action="#{localeSelector.change}">
<f:param name="language" value="fr" />
</h:commandButton>
with
public void change() {
locale = new Locale(FacesContext.getCurrentInstance().getExternalContext().getRequestParameterMap().get("language"));
// ...
}
(you can also let JSF automatically set it by a #ManagedProperty("#{param.language}"), but this requires the bean to be request scoped, or a <f:viewParam>, see also ViewParam vs #ManagedProperty(value = "#{param.id}"))
Enough ways to pass a parameter from view to controller. Take your pick. The <h:inputHidden> serves in JSF context a somewhat different purpose and it can only be manipulated by JavaScript in the onclick which is ugly.
I want to find out the previous page from where the current page is called. Based on the previous page I want to enable or disable a particular component. Can anybody help me in this regard.
Depends on the concrete functional requirement which isn't entirely clear from your question. You could pass an unique request parameter. E.g. when it concerns a GET link:
<h:link value="Next" outcome="next">
<f:param name="foo" value="bar" />
</h:link>
or a POST link:
<h:form>
<h:commandLink value="Next" action="next">
<f:param name="foo" value="bar" />
</h:commandLink>
</h:form>
with in next.xhtml
<h:someComponent rendered="#{param.foo == 'bar'}">
...
</h:someComponent>
or if you don't care about the param's value:
<h:someComponent rendered="#{not empty param.foo}">
...
</h:someComponent>
An alternative which can be much better if you don't want to allow the enduser being able to manipulate the request is to set a bean property during a POST action and then return to the next view:
<h:form>
<h:commandLink value="Next" action="#{bean.next}" />
</h:form>
with e.g.
public String next() {
foo = "bar";
return "next";
}
and in next.xhtml
<h:someComponent rendered="#{bean.foo == 'bar'}">
...
</h:someComponent>