This question already has an answer here:
How to validate availability of username in database?
(1 answer)
Closed 5 years ago.
I need to know if there is a way to do real-time validation using Primefaces/JSF?
My requirement looks simple:
I've an input box which would take only unique name. For eg.., if an user is looking to input an name which already exists in database, it
should throw error message like "User Name already exists." This
should happen as soon as the user has moved out of the input box
Reference can be inferred from Google registration page
I've spent a lot of time researching on internet but haven't arrived at any concrete solution.
I'm primarily looking for a solution in Primefaces/JSF. Is it possible?
You can do that with plain JSF. You just have to use a validator and add ajax behavior to your input field, e.g.
facelet
<h:form id="form">
<h:messages id="messages" />
<h:inputText value="#{anyBean.username}" validator="userValidator">
<f:ajax render="#this messages" />
</h:inputText>
</h:form>
validator
#FacesConverter("userValidator")
public class UserValidator implements Validator {
#Override
public void validate(FacesContext fc, UIComponent component, Object value) throws ValidatorException {
String username = (String) value;
if (usernameExists(username)) {
throw new ValidatorException(new FacesMessage("User Name already exists."));
}
}
private boolean usernameExists(String username) {
// check if username exists here
}
}
Of course you can also use the equivalent PrimeFaces components p:messages, p:inputText and p:ajax.
Related
I'm using Primefaces version 5.3 autocomplete in a web project, I have written the search method and converter for the java entities i am searching for. These all work well the selected entity from the autocomplete is set correctly in the backing bean using a p:ajax tab and initially the entity name, which i specify in the itemValue, is set in the text input.
When i then submit the form that includes this autocomplete the variable in the backing bean which i set from the autocomplete stays as it is which is intended but the text input on the autocomplete will display the entities id instead of the name as i'd specified on the itemValue. This is because it is calling the toString method in my converter but I want it still to display the name yet i need the converter..
Has anyone come across this issue that may be able to help?
I have found a thread else where that describe this behaviour but it is a couple years old now and doesn't have an answer.
This thread is:
http://forum.primefaces.org/viewtopic.php?f=8&t=37918
As it may explain it better than i have...
Any help is appreciated.
UPDATE: code added
Here is my autocomplete tag, complete method returns a java List of entity type.
<h:form>
<p:autoComplete id="autocomplete" value="#{bean.selectedEntity}"
completeMethod="#{bean.listOfPossibleEntities}"
itemValue="#{_e}" itemLabel="#{_e.name}" autocomplete="off"
minQueryLength="3" var="_e"
placeholder="Enter Entity Name Here"
converter="EntityConverter" forceSelection="true">
<p:ajax event="itemSelect" update="enclosingForm"/>
<p:column>
<h:outputText value="#{_e.name}" />
</p:column>
</p:autoComplete>
<p:commandButton update="#form" >
</h:form>
FacesConverter looks like as below, i use a DAO call to our database find the object for each id
private EntityDAO entityDAO = (EntityDAO)Component.getInstance("entityDAO");
#Override
public Object getAsObject(FacesContext context, UIComponent component, String value) {
Integer id = Integer.valueOf(value);
return entityDAO.findById(id,false);
}
#Override
public String getAsString(FacesContext fc, UIComponent uic, Object object) {
String result = "";
if(object != null) {
if(object instanceof Entity){
result = ""+ String.valueOf(((Entity) object).getEntityId());
}
}
return result;
}
So yes on update of the h:form after the entity on the autocomplete is selected and the submitting with the p:commandButton the value display or the entity will change from the entity name to the entity id.
Hope this helps further thanks.
This question already has answers here:
How do I process GET query string URL parameters in backing bean on page load?
(4 answers)
Closed 7 years ago.
I have a few managed bean (ViewScoped) that are currently initialized with data in the session. I would like to initialize them with a URL GET parameter so I can provide URLs with the entity ID I want to display in my view. Something like displayClient.xhtml?entityId=123.
Right now I am thinking of something like this in the getter of the view main entity :
public clientModel getclientM() {
if (this.clientM == null) {
// TODO: Check for empty, non-integer or garbage parameters...
// Anything exists to "sanitize" URL parameters?
int entityId = Integer.parseInt(FacesContext.getCurrentInstance().getExternalContext().getRequestParameterMap().get("entityId"));
// I guess I should check here if the logged user is authorized to
// load client entity with this entityId... anything else to check?
this.clientM = this.clientS.find(entityId);
}
return this.clientM;
}
Any hint or suggestion of best practices would be greatly appreciated.
I'd think something along these lines are best practice:
displayclient.xhtml:
<f:metadata>
<f:viewParam name=“entityId”
value="#{bean.clientM}”
required="true"
converter=“clientModelConverter”
converterMessage="Bad request. Unknown ClientModel.”
requiredMessage="Bad request. Please use a link from within the system.">
</f:viewParam>
</f:metadata>
Converter:
#ManagedBean
#RequestScoped
public class ClientModelConverter implements Converter {
#EJB
private ClientService clientService;
#Override
public String getAsString(FacesContext context, UIComponent component, Object value) {
// TODO: check if value is instanceof ClientModel
return String.valueOf(((ClientModel) value).getId());
}
#Override
public Object getAsObject(FacesContext context, UIComponent component, String value) {
// TODO: catch NumberFormatException and throw ConverterException
return clientService.find(Integer.valueOf(value));
}
}
Call the page with for example:
<h:link value=“Display” outcome="displayClient">
<f:param name=“entityId" value=“#{…}” />
</h:link>
or just a raw url for example displayClient.xhtml?entityId=123.
Heavily inspired by
What can <f:metadata>, <f:viewParam> and <f:viewAction> be used for? and
JSF 2.0 view parameters to pass objects.
Store entityId in session, for example SessionScoped Bean
In your View Scoped managed beans, add #PostConstruct method, where you will get entityId from session and populate data with this
I did something similar, for the same exact reason : Providing an external link to a jsf page.
In your ViewScoped bean, have a #PostConstruct method to force a fail-safe scan for the Get Param
#PostConstruct
public void scanEntityId(){
int entityId = 0; // or some other default value
try{
// Try to fetch entityId from url with GET
int entityId = Integer.getInteger(FacesContext.getExternalContext().getRequestParameterMap().get("entityId") );
}catch(Exception e){
// Did not find anything from GET
}
// TODO: do stuff using the entityId's value. e.g.:
if(entityId >0){
this.clientM = this.clientS.find(entityId);
}
}
Just make sure to handle the cases where the entityId var is not found in the Get params
If you want to link to that page from another xhtml page of the same app, you can use the f:param
<h:link value="Go in a page that uses thatViewScoped Bean"
outcome="#{thatViewScopedBean.takeMeToThatPage}" >
<f:param name="entityId" value="#{somebean.somevar.entityId}" />
</h:link>
A nice tutorial can also be found here
You might also like to see this answer, and this article to see more options and get a more clear view.
I have the following problem. I use a form when I provide only PIN. I have validator which checks if its a 4-digit number. Then the action on submit is set to the method which checks if the PIN exists in the database. If not it does message = "no PIN"; I used the message in the output label below the form. Previously it was null so there was no message there. Now it changes into "no PIN" but I have to clear it after clicking the submit button again because the error message doesn't disappear when you enter for example "12as" PIN and validator takes care of it. How should i implement such situation? Maybe using an output label in such situtation is a wrong idea?
You should not perform validation in action method. You should use a real validator.
Just implement the Validator interface accordingly. E.g.
#FacesValidator("pinValidator")
public class PinValidator implements Validator {
#Override
public void validate(FacesContext context, UIComponent component, Object value) throws ValidatorException {
String pin = (String) value;
if (pin == null || pin.isEmpty()) {
return; // Let required="true" deal with it if necessary.
}
if (!pin.matches("\\d{4}")) {
throw new ValidatorException(new FacesMessage("PIN must be 4 digits"));
}
if (!somePinService.exists(pin)) {
throw new ValidatorException(new FacesMessage("PIN is unknown"));
}
}
}
Use it as follows:
<h:outputLabel for="pin" value="PIN" />
<h:inputText id="pin" value="#{bean.pin}" validator="pinValidator" />
<h:message for="pin" />
The faces message of the validator exception will end up in the <h:message> associated with the component on which the validator is been fired.
If you're using ajax to submit the form, don't forget to make sure that the message is also taken into account on ajax render.
Unrelated to the concrete problem, the JSF <h:outputLabel> generates a HTML <label> element which is intented to label a form element (e.g. <input>, <select>, etc). It's absolutely not intented to show an arbitrary piece of text such as a validation message. I recommend to put JSF aside for now and start learning basic HTML. This way you will understand better which JSF components to pick to get the desired HTML output.
You can use JSF message component outside a validator:
For a message for your input in your form:
<h:message for="PIN"/>
And at your managed bean you can add a FacesMessage using:
FacesMessage message = new FacesMessage(FacesMessage.SEVERITY_WARN,"No pin summary message","No pin detail message");
FacesContext.getCurrentInstance().addMessage("PIN", message);
No need to use a outputLabel here.
I spent already more time as is good about some saving or updating issue in inputtext field, i go right to the point:
i have basic single input text with some basic attributtes
<h:inputText id="name" value="#{salesController.selectedSalesName}" />
here is a getter for inputText value
public String getSelectedSalesName(){
for(DealerListView dealer : dealerList){
if(dealer.getDealerId() == getSelectedDealerId()){
return dealer.getName();
}
}
return "";
}
nested in there i use ajax tag
<f:ajax event="change" render="name" listener="#{salesController.updateSelectedSalesName()}" />
a here is back bean method for updating a input text field
public void updateSelectedSalesName() {
DealerData dealDat = BeanFactory.getHotelDAOService(DealerData.class).findOne(selectedDealerId);
dealDat.setName(name);
BeanFactory.getHotelDAOService(DealerData.class).update(dealDat);
}
whole result of this is stack trace which say
value="#{salesController.selectedSalesName}": Property 'selectedSalesName' not writable on type sk.hotel.web.controller.SalesController
I know that something changes is need for that getter method but try some combinations without result which make corect update of value to database.
(I dont use any commands buttons for submit,update only response on pressing Enter in that inputText field.)
I want some guide how can be modified this save/update process whether on back-bean or jsf layout
or maybe someone solved similar situation already,and can share his solution.
Thanks all of you for advice posts.
Regards and nice day
First, add a field:
String selectedSalesName;
Add a setter and setter:
public String getSelectedSalesName() {
return selectedSalesName;
}
public void setSelectedSalesName(String selectedSalesName) {
this.selectedSalesName = selectedSalesName;
}
Add a ajaxListener(AjaxBehaviurEvent event) to create a new Dealer or Update current Dealer
public void ajaxListener(AjaxBehaviorEvent event) {
Dao dao = BeanFactory.getHotelDAOService(DealerData.class)
if (selectedDealerId == null) {
DealarData dealerData= new DealerData();
dealerDate.setName(getSelectedSalesName());
dao.add(dealerData);
setDealer(dealerData);
} else {
DealerData dealDat = dao.findOne(selectedDealerId);
dealDat.setName(name);
dao.update(dealDat);
}
}
A setter to the current dealer
int selectedDealerId;
public void setDealer(DealerData dealer) {
selectedDealerId = dealer.getId();
selectedSalesName = dealer.getName();
}
And the xhtml page:
<h:inputText value="#{salesController.selectedSalesName}" id="idSalesInput">
<a4j:ajax event="keyup" listener="#{salesController.ajaxListener}"
execute="idSalesInput"/>
</h:inputText>
Change "keyup" for the event you want to listen.
When you press a key, the listener is called, and the value of idSalesInput is submitted (the setSelectedSalesName() method is called here, for this reason you got the Property 'selectedSalesName' not writable exception),and the listener create or update a new DealerData.
Have a nice Day and sorry for my bad english!
Binding value in your inputText is two way, when it is rendered than getter is called to calculate value, when it is submited (like in your AJAX event) setter is called for that property to set value in your backing bean. So JSF tries to call setSelectedSalesName(String value). JSF can't write your property, which means can't call setter.
See also:
AJAX listener not being fired for inside
This question already has answers here:
Validation Error: Value is not valid
(3 answers)
Closed 7 years ago.
I have this SelectOneMenu:
<h:selectOneMenu value="#{orderController.requestVO.requestSituation}">
<f:converter converterId="ComboConverter"/>
<f:selectItems value="#{orderController.requestSituation}" var="requestSituation"
itemLabel="#{requestSituation.description}" itemValue="#{requestSituation}" />
</h:selectOneMenu>
The requestSituation is a ArrayList filled with RequestSituationVO
It is populated correctly, generating this HTML:
<select name="j_idt14:j_idt20" size="1">
<option value="13">Pedido Recusado</option>
<option value="11">Pedido Validado</option>
<option value="12" selected="selected">Pedido Confirmado</option>
<option value="12" selected="selected">Pedido Faturado</option>
</select>
I have this Converter and here is where I'm confused, I've read a lot and I know what it has to do but not how it works.
Here it is:
#FacesConverter(value = "ComboConverter", forClass = RequestSituationVO.class)
public class ComboConverter implements Converter
{
private static RequestSituationVO requestSituationVO = new RequestSituationVO();
#Override
public Object getAsObject(FacesContext context, UIComponent component, String value)
{
requestSituationVO.setId(Integer.valueOf(value));
requestSituationVO = (RequestSituationVO) new RequestSituationBO().getRequestSituation(requestSituationVO).toArray()[0];
return (RequestSituationVO) requestSituationVO;
}
#Override
public String getAsString(FacesContext context, UIComponent component, Object value)
{
requestSituationVO = (RequestSituationVO) value;
String teste = String.valueOf(requestSituationVO.getId());
return teste;
}
}
When I submit my page, I think the SelectOneMenu will automatically set the value for the requestSituation method from requestVO. But when I submit, I get a message Value not valid referencing to my SelectOneMenu.
What I need is to set the selected value on my RequestSituationVO so I can send it to the Business method.
Your converter is fine. You would otherwise have gotten a conversion error something like
Conversion Error setting value 'com.example.RequestSituationVO#hashcode' for 'null Converter'
You've a validation error. This particular one will be thrown when the Object#equals() test of the selected item hasn't returned true for any of the available items in the list. JSF is checking that to prevent attacks by tampered requests. This can in your particular case have the following causes:
The equals() method of the RequestSituationVO class is missing or broken.
The #{orderController.requestSituation} has incompatibly changed in between the request of displaying the form and the request of processing the form submit.
I think that it's the former. Given the fact that your RequestSituationVO has an Integer id property which uniquely identifies the object, this should do:
#Override
public boolean equals(Object other) {
return (other instanceof RequestSituationVO) && (id != null)
? id.equals(((RequestSituationVO) other).id)
: (other == this);
}
#Override
public int hashCode() {
return (id != null)
? (this.getClass().hashCode() + id.hashCode())
: super.hashCode();
}
If the equals() method is not the problem, then it's the latter cause. This can be solved by making sure that the #{orderController.requestSituation} returns exactly the same list during displaying the form and processing the form submit. This can be achieved by placing the bean in the view scope and not doing the business logic in the getter at all. Or if it actually represents applicationwide data, you could refactor it to a separate application scoped bean.
See also
Our selectOneMenu wiki page
It looks like you forgot to implement equals and hashCode in RequestSituation.
This is very important, as JSF will compare the submitted value against all the given items.
If you don't implement equals, it thinks the submitted item is not in the list,
so it rejects it. (The value is not valid.)