I am newbie to JSF/Java ee7 and tried to test some features to understand how things work.
I used templating for testing purposes. Here is the relevant JSF template client:
<ui:define name="content">
<h:panelGroup class="keret" id="tartalom">
<h:form id="email" rendered="#{emailManagedBean.urlap}">
<h:messages/>
<h:outputLabel for="emailbox" value="Add meg az email címed, és juss hozzá bestsellerünkhöz 5Ft-ért"/>
<h:inputText value="#{emailManagedBean.newEmail.email}"/>
<h:commandButton actionListener="#{emailManagedBean.saveEmail()}" value="Mentés">
<f:ajax immediate="true" execute="#form" render=":tartalom"/>
</h:commandButton>
</h:form>
<h:panelGroup id="szoveg" rendered="#{not emailManagedBean.urlap}">
<h3>Köszönjük!</h3>
<p>
Hamarosan emailt fogsz kapni tőlünk. Kérlek, ellenőrizd a levélszemét, illetve spam mappákban is a tőlünk kapott levelet. A levlében lévő linkre kattintva hozzájuthatsz az ajándékodhoz.
</p>
</h:panelGroup>
</h:panelGroup>
</ui:define>
My managed bean:
#Named(value = "emailManagedBean")
#ViewScoped
public class emailManagedBean implements Serializable {
#EJB
EmailsFacadeLocal emailFacade;
private Emailcamp newEmail;
private boolean urlap;
public Emailcamp getNewEmail() {
return newEmail;
}
public void setNewEmail(Emailcamp newEmail) {
this.newEmail = newEmail;
}
#PostConstruct
public void init() {
newEmail = new Emailcamp();
urlap=true;
}
public boolean isUrlap() {
return urlap;
}
public void setUrlap(boolean urlap) {
this.urlap = urlap;
}
public void validateEmail(FacesContext context, UIComponent comp,
Object value) {
String input = (String) value;
EmailValidator validator = EmailValidator.getInstance();
if (!validator.isValid(input)) {
((UIInput) comp).setValid(false);
FacesMessage message = new FacesMessage(
"Helytelen email cím formátum");
context.addMessage(null, message);
} else {
if(!emailFacade.exist(newEmail.getEmail())){
((UIInput) comp).setValid(true);
}
else {
context.addMessage(null, new FacesMessage("Már megadtad korábban az email címed"));
}
}
}
public void saveEmail() {
/*Get current date and time*/
Calendar c = Calendar.getInstance();
newEmail.setRecemaildate(c.getTime());
/*Get Referral*/
HttpServletRequest hr = (HttpServletRequest) FacesContext.getCurrentInstance().getExternalContext().getRequest();
newEmail.setReferer((hr.getHeader("referer")==null) ? "not available" : hr.getHeader("referer") );
newEmail.setStatus(Status.NOT_SENT.toString());
emailFacade.create(newEmail);
urlap=false;
}
}
The expected behavior is that the init function set urlap boolean variable to true so the h:form should be shown as there is conditional rendering on the view side.
Later the customer clicks on Save ("Mentés") and the new email address and some data will be stored in a database. After the ajax call I urlap boolean varaible is set to false not to render the form again but render a thank you message.
Unfortunately the init function is never called so the boolean variable never set to true. As a consequences my thanks message is shown without collecting the email.
The second strange thing which is the consequence of the ajax component (I guess) that I got an error message: outputScript with no library, no name, and no body content. I did not declare any outputScript in my xhtml.
Related
I am writting a simple user registration process.What I want to do is that when the user enters a username, I want to check if the username has already been taken by someone else. If it has been, then I want to show a message under the input field, asking the user to choose a different username.
I have already written the database query/ejb/rest etc...
What I want to know is ... How do I make a call to the backend (ejb/rest) and show the message on the screen without having to make a full round trip to the server and refreshing the entire page?
Update 1:
I have changed my code to look like the example from Simon.(Don't know why it did not appear before).
<h:form>
<h:panelGrid columns="2">
<h:outputLabel for="username" value="Please enter a user name :" />
<h:inputText id="username" value="#{userNameCheckBean.signInName}"
autocomplete="off" size="20" onfocus="blankOut();" required="true"
requiredMessage="Error: Username is required." maxlength="25">
<f:ajax execute="#this" render="message" listener="#{userNameCheckBean.verifyIfUsernameIsAlreadyTaken()}" />
</h:inputText>
<h:outputText rendered="#{userNameCheckBean.userExists}" id="message" value="#{userNameCheckBean.message}" />
</h:panelGrid>
<h:commandButton id="checkUser" action="#{userNameCheckBean.userExists}" value="Check">
</h:commandButton>
</h:form>
The confusing thing for me is, How do I call the verifyIfUsernameIsAlreadyTaken() method when the username inputText looses focus? and how do I update just the bit of the overall form? Is it a must to have a commandButton to submit the username field? I thought ajax was meant to make server calls in the background.
Update 2:
I have changed the .xhtml file to the one given below. I still have to click on the button to call the backing bean. It simply ignores the event. Any help will be much appriciated.
<h:form>
<h:panelGrid columns="2">
<h:outputLabel for="username" value="Please enter a user name :" />
<h:inputText id="username" value="#{userNameCheckBean.signInName}" autocomplete="off" size="20" onfocus="blankOut();" required="true" requiredMessage="Error: Username is required." maxlength="25">
<f:ajax execute="#this" event="blur" render="message" listener="#{userNameCheckBean.checkIfUsernameIsAlreadyTaken()}" />
</h:inputText>
<h:panelGroup>
<h:outputText rendered="#{userNameCheckBean.userExists}" id="message" value="#{userNameCheckBean.message}" />
</h:panelGroup>
</h:panelGrid>
<h:commandButton id="checkUser" action="#{userNameCheckBean.checkIfUsernameIsAlreadyTaken}" value="Check">
</h:commandButton>
</h:form>
Update 3:
Here is backing bean that works when I click on the Button.
package co.uk.dakia.beans;
import java.io.IOException;
import java.util.logging.Logger;
import javax.ejb.EJB;
import javax.faces.bean.ManagedBean;
import javax.faces.bean.RequestScoped;
import javax.faces.event.AjaxBehaviorEvent;
import javax.naming.NamingException;
import javax.validation.constraints.NotNull;
import example.UserManager;
import example.ServiceLocator;
#ManagedBean
#RequestScoped
public class UserNameCheckBean {
private static Logger logger = Logger.getLogger(UserNameCheckBean.class.getName());
#EJB(beanName = "UserManager", mappedName = "jndi:ext://example/UserManagerRemote")
UserManager userManager;
String signInName;
String password;
String message = "Message: ";
boolean userExists = false;
public void checkIfUsernameIsAlreadyTaken(AjaxBehaviorEvent event) throws NamingException, IOException {
userManager = (UserManager) ServiceLocator.locateService("UserManagerRemote");
logger.info("Checking if username [" + signInName + "] has already been taken by some other user");
userExists = userManager.userExists(signInName);
if(userExists) {
message = "Username is already taken!";
} else {
message = "";
logger.info("Username [" + signInName + "] is available.");
}
}
public void checkIfUsernameIsAlreadyTaken() throws NamingException, IOException {
checkIfUsernameIsAlreadyTaken(null);
}
public String getSignInName() {
return signInName;
}
public void setSignInName(String signInName) {
this.signInName = signInName;
}
public String getMessage() throws NamingException, IOException {
checkIfUsernameIsAlreadyTaken();
return message;
}
public void setMessage(String message) {
this.message = message;
}
public boolean isUserExists() {
return userExists;
}
public void setUserExists(boolean userExists) {
this.userExists = userExists;
}
public String getPassword() {
return password;
}
public void setPassword(String password) {
this.password = password;
}
}
You did not provide any code so it is hard to tell you exactly what to do, but here's a template (assuming you're using JSF 2):
.xhtml:
<h:form>
...
<h:inputText id="username" value="#{myBean.username}">
<f:ajax execute="#this" render="username-already-taken-wrapper" listener="#{myBean.verifyIfUsernameIsAlreadyTaken()}"/>
</h:inputText>
<h:panelGroup id="username-already-taken-wrapper">
<h:outputText rendered="#{myBean.usernameAlreadyTaken}" value="Username is already taken!"/>
</h:panelGroup>
...
</h:form>
MyBean.java:
public void verifyIfUsernameIsAlreadyTaken()
{
usernameAlreadyTaken = verify(username);
}
private boolean verify(String username)
{
...
}
The trick is to use AJAX to submit only a part of your form (in this case: the username), and refresh only a part of the page (in this case: username-already-taken-wrapper). If the username is already taken, the message will show. If not, nothing will show.
I'm trying to invoke a <f:ajax listener> method on change of <h:selectOneMenu>.
This is the view:
<h:selectOneMenu label="verteilerlisten"
value="#{smsBean.verteilerliste}" id="verteilerlisten">
<f:ajax listener="#{smsBean.verteilerlistenChanged}"
render="verteilerlisten" />
<f:selectItems value="#{verteilerlisten.list}"
var="v" itemLabel="#{v.name}" itemValue="#{v.verteilerlistennummer}" />
</h:selectOneMenu>
This is the #{smsBean}:
public void verteilerlistenChanged(AjaxBehaviorEvent e) {
System.out.println("success!");
throw new RuntimeException("Success!");
}
The items are displayed correctly, but nothing happens when I change the item in the select box. How is this caused and how can I solve it?
EDITED:
I created a blank xhtml file (test.xhtml) with the following code:
<?xml version="1.0" encoding="UTF-8"?>
<!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:h="http://java.sun.com/jsf/html"
xmlns:f="http://java.sun.com/jsf/core">
<h:head />
<h:body>
<h:form id="smsform">
<h:selectOneMenu label="verteilerlisten" value="#{smsBean.verteilerliste}"
id="verteilerlisten">
<f:selectItems value="#{verteilerlistenBean.list}" var="v"
itemLabel="#{v.name}" itemValue="#{v.verteilerlistennummer}"/>
<f:ajax listener="#{smsBean.verteilerlistenChanged}" render="smsform"/>
</h:selectOneMenu>
</h:form>
</h:body>
</html>
This is the VerteilerlistenBean.java:
#ManagedBean(name= "verteilerlistenBean")
#ApplicationScoped
public class VerteilerlistenBean {
private Logger logger = Logger.getLogger(VerteilerlistenBean.class);
private List<Verteilerliste> list = new ArrayList<Verteilerliste>();
public VerteilerlistenBean() {
}
public List<Verteilerliste> getList() {
// return list;
logger.info("Getter invoked");
List<Verteilerliste> list = new ArrayList<Verteilerliste>();
list.add(new Verteilerliste(1, "Liste 1"));
list.add(new Verteilerliste(2, "Liste 2"));
list.add(new Verteilerliste(3, "Liste 3"));
list.add(new Verteilerliste(4, "Liste 4"));
list.add(new Verteilerliste(5, "Liste 5"));
return list;
}
public void setList(final List<Verteilerliste> parList) {
list = parList;
}
}
And this is the smsBean (SendSMSFormBean.java):
#ManagedBean (name="smsBean")
#ViewScoped
public class SendSMSFormBean implements Serializable {
private String absender;
private Verteilerliste verteilerliste;
private Textbaustein textbaustein;
public SendSMSFormBean() {
}
public String getAbsender() {
return absender;
}
public void setAbsender(final String parAbsender) {
absender = parAbsender;
}
public Verteilerliste getVerteilerliste() {
return verteilerliste;
}
public void setVerteilerliste(final Verteilerliste parVerteilerliste) {
verteilerliste = parVerteilerliste;
}
public Textbaustein getTextbaustein() {
return textbaustein;
}
public void setTextbaustein(final Textbaustein parTextbaustein) {
textbaustein = parTextbaustein;
}
public void verteilerlistenChanged(AjaxBehaviorEvent e) {
System.out.println("Success!");
}
}
These are my libs I use:
(I can't upload image -.- )
javassist-3.15.0-GA.jar
javax.faces-2.0.11.jar
javax.servlet-5.1.12.jar
javax.servlet-api-3.0.1.jar
javax.servlet.jar
javax.servlet.jsp.jstl-1.2.1.jar
EDITED 2
I cleaned my classpath lib so that all these classes aren't inside there anymore (it uses the libs from tomcat now). I also added a in the plain example (i got a in the main example). But still everytime I change the value in the selectBox in the console appears:
2014-01-21 16:03:48 INFO VerteilerlistenBean:44 - Getter invoked
EDITED 3
When changing f:ajax listener attribute to "#{asdf.asdf}. No error was shown! Before that I tried #{smsBean.verteilerlistenChanged} and ${smsBean.verteilerlistenChanged}
EDITED 4
So now I think I got the mistake:
<div class="ym-fbox">
<h:selectOneMenu label="verteilerlisten" id="verteilerlisten">
<f:selectItems value="#{testbean.list}" var="v" itemLabel="#{v.name}" itemValue="#{v.id}"/>
<f:selectItem itemLabel="Manuelle Eingabe" itemValue="man"/>
<f:ajax listener="#{testbean.beep}" render="smsform"/>
</h:selectOneMenu>
</div>
<div class="ym-fbox">
<h:selectOneMenu label="verteilerlisten1" id="verteilerlisten1" value="#{smsBean.verteilerliste}">
<f:selectItems value="#{verteilerlistenBean.verteilerlisten}" var="liste" itemLabel="#{liste.name}" itemValue="#{liste.verteilerlistennummer}" />
<f:selectItem itemLabel="Manuelle Eingabe" itemValue="man"/>
<f:ajax listener="#{testbean.beep}" render="smsform"/>
</h:selectOneMenu>
</div>
The upper one invokes testbean.beep when changed the other one doesn't! It would work if you remove attribute "value" in selectOneMenu. I don't know why JSF does this or why it doesn't show me any error..
But that doesn't solve my problem: I have 2 Beans. One is a Bean, that safes the inputs in the form (smsBean). The select Value should be saved in this bean. The other bean is something like a RessourceManager, which returns the values that the user can select in the box.
How do I make this?
I observed following behaviour in JSF:
A UIInput component triggered via AjaxBehaviour with 'immediate=true' does not have the validator executed in the APPLY_REQUEST, but always in the Phase determined by the UIInput itself. It means the AjaxBehaviour 'immediate' attribute has no effect on when the validator of the component is processed. Which is IMO not what the describtion of AjaxBehaviour says:
The immediate attribute indicates whether user inputs are to be processed early in the application lifecycle or later. If the attribute is set to true, events generated from this component are broadcast during the Apply Request Values phase. Otherwise, the events will be broadcast during the Invoke Applications phase.
To be read at: Oracle Tutorial
Even thought in AjaxBehaviour.isImmediate(component,behaviour) JSF takes care of having the AjaxBehaviour more important than the component
private boolean isImmediate(UIComponent component, AjaxBehavior ajaxBehavior) {
boolean immediate = false;
if(ajaxBehavior.isImmediateSet()) {
immediate = ajaxBehavior.isImmediate();
} else if(component instanceof EditableValueHolder) {
immediate = ((EditableValueHolder)component).isImmediate();
} else if(component instanceof ActionSource) {
immediate = ((ActionSource)component).isImmediate();
}
return immediate;
}
Whereas in the UIInput.processDecodes(context) does not trigger the validation in that phase because the component is not 'immediate' ..
public void processDecodes(FacesContext context) {
if (context == null) {
throw new NullPointerException();
}
// Skip processing if our rendered flag is false
if (!isRendered()) {
return;
}
super.processDecodes(context);
if (isImmediate()) {
executeValidate(context);
}
}
Anyways; to reproduce my case:
A) The JSF code:
<h:selectBooleanCheckbox id="mandatory" value="#{currentQuestion.mandatory}" label="#{texts.mandatory_Question}" disabled="#{!bean.metadata.editable}" validator="mandatoryValidator" onchange="makeDirty()" immediate="false">
<f:ajax event="click" execute="#this" render="#this :mandatory-msg" immediate="true"/>
</h:selectBooleanCheckbox>
<h:outputLabel for="mandatory" value="#{texts.mandatory_Question}" styleClass="standard-label chkBox-label" />
<p:message for=":mandatory" id="mandatory-msg" showDetail="true" showSummary="true" />
B)The custom validator:
#FacesValidator("mandatoryValidator")
public class MandatoryValidator implements Validator {
/** logger. */
private static final Logger LOG = Logger.getLogger(MandatoryValidator.class.getName());
/** {#inheritDoc} */
#Override
public final void validate(final FacesContext context, final UIComponent component, final Object value) {
if (FacesContext.getCurrentInstance().getCurrentPhaseId() == PhaseId.APPLY_REQUEST_VALUES) {
LOG.debug("apply phase");
}
if (FacesContext.getCurrentInstance().getCurrentPhaseId() == PhaseId.PROCESS_VALIDATIONS) {
LOG.debug("validation phase");
}
}
In that example the validator will not be executed in the APPLY_REQUEST until the SelectBoolCheckBox is also 'immediate=true'. Even worse, the immediate of the component, even defaulted, always wins. Which makes the AjaxBehaviour immediate attribute totally worthless.
Can anyone explain or reproduce or grunt with me?
I use Richfaces. I am facing a situation where I have a form and 2 buttons. On click of one of the buttons, say button1, I need the validations. On click of another, button2, I dont. The issue arises when I click on the button1 and I get all validation error messages. This prevents clicking of button2. I tried ajaxSingle, immediate, which help in bypassing the validations but bean values are not updated. How can I achieve that ?
Code :
<h:inputSecret value="#{bean.value} redisplay="true"/>
<a4j:commandButton immediate="true" actionListener="#{bean.actionListener} reRender="ID_OF_PANEL_SURROUNDING_THIS_CODE"/>
Bean :w
public class bean {
.
.
.
public void actionListener(ActionEvent e) {
value = "New value";
}
.
.
.
}
Set immediate attribute to true in your second button.
Immediate attribute skips validation of your values but using immediate for anything other than the trivial case of a cancel button is problematic. If your button2 is some kind of cancel button there is no problem.
If you need to implement something more complex than a cancel button there are some solutions to these problems which you can find in below article.
How_The_Immediate_Attribute_Works
What is actually possible to do for such case is writing a custom validator and do the relevant checks in it.
conditionalValidation.xhtml:
Please notice the h:inputHidden that agregate ids and trigger custom validator to be invoked.
<ui:composition 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:c="http://java.sun.com/jstl/core"
xmlns:a4j="http://richfaces.org/a4j"
xmlns:rich="http://richfaces.org/rich"
template="/WEB-INF/template/default.xhtml">
<ui:param name="title" value="Conditional Validation"/>
<ui:param name="bean" value="#{conditionalValidationBean}"/>
<ui:define name="content">
<a4j:form id="frmConditionalValidation">
<h:panelGrid columns="2">
<h:outputLabel for="txtValue1" value="Value 1"/>
<h:panelGroup>
<h:inputText id="txtValue1" value="#{bean.value1}"/>
<h:message for="txtValue1"/>
</h:panelGroup>
<h:outputLabel for="txtValue2" value="Value 2"/>
<h:panelGroup>
<h:inputText id="txtValue2" value="#{bean.value2}"/>
<h:message for="txtValue2"/>
</h:panelGroup>
</h:panelGrid>
<h:inputHidden id="inpDetailsProvider" required="true"
validator="#{bean.conditionalValidator}" value="1">
<f:attribute name="forceValidationBtnId" value="btnForceValidation"/>
<f:attribute name="value1InputId" value="txtValue1"/>
<f:attribute name="value2InputId" value="txtValue2"/>
</h:inputHidden>
<h:commandButton id="btnForceValidation" value="Force Validation"/>
<h:commandButton id="btnByPassValidation" value="Bypass Validation"/>
</a4j:form>
</ui:define>
</ui:composition>
ConditionalValidationBean.java
public class ConditionalValidationBean {
private String value1;
private String value2;
#SuppressWarnings("unused")
public void conditionalValidator(FacesContext context, UIComponent component, Object value) {
String forceValidationBtnId = (String) component.getAttributes().get("forceValidationBtnId");
String value1InputId = (String) component.getAttributes().get("value1InputId");
String value2InputId = (String) component.getAttributes().get("value2InputId");
UIViewRoot viewRoot = FacesContext.getCurrentInstance().getViewRoot();
UICommand forceValidationBtn = findComponent(viewRoot, forceValidationBtnId, UICommand.class);
Map<String, String> params = context.getExternalContext().getRequestParameterMap();
boolean forceValidation = params.containsKey(forceValidationBtn.getClientId(context));
if(forceValidation) {
UIInput value1Input = findComponent(viewRoot, value1InputId, UIInput.class);
UIInput value2Input = findComponent(viewRoot, value2InputId, UIInput.class);
String v1 = (String) value1Input.getValue();
if(v1 == null || v1.trim() == "") {
value1Input.setValid(false);
FacesMessage valueRequiredMsg = new FacesMessage("Value required");
context.addMessage(value1Input.getClientId(context), valueRequiredMsg);
}
// Rest of validation logic.
}
}
public static <T> T findComponent(UIComponent base, String id, Class<T> returnType) {
if (id.equals(base.getId())) {
return returnType.cast(base);
}
Iterator<UIComponent> children = base.getFacetsAndChildren();
while (children.hasNext()) {
T found = findComponent(children.next(), id, returnType);
if (found != null) {
return returnType.cast(found);
}
}
return null;
}
public String getValue1() {
return value1;
}
public String getValue2() {
return value2;
}
public void setValue1(String value1) {
this.value1 = value1;
}
public void setValue2(String value2) {
this.value2 = value2;
}
}
Im trying JSF framework. Im a beginner. So i start with a easy tutorial. This is the code :
<h:form id="form1" prependId="false">
<h:outputScript name="jsf.js" library="javax.faces" target="head" />
<h:inputText value="#{user.name}" id="name"/>
<h:inputSecret value="#{user.password}" id="password"/>
<h:outputText value="#{user.greeting}" id="out"/>
<br/>
<h:commandButton value="Login" type="button" onclick="jsf.ajax.request(this, event, {execute: 'name password', render: 'out'}); return false;" />
</h:form>
import javax.faces.bean.ManagedBean;
import javax.faces.bean.RequestScoped;
#ManagedBean(name = "user")
#RequestScoped
public class UserBean {
private String name = "";
private String password;
public String getName() { return name; }
public void setName(String newValue) { name = newValue; }
public String getPassword() { return password; }
public void setPassword(String newValue) { password = newValue; }
public String getGreeting() {
if(name.length()==0) {
return "Inserisci nickname";
} else {
return "Benvenuto "+name;
}
}
}
In "less words" (when i click on button) :
1 - thanks to execute: 'name password, I call the setName and setPassword (JavaBean methods) with an asynch call;
2 - than, thanks to render: 'out' I call getGreeting
So, execute will be translate as SET and render as GET.
What I would like to know is if I have well understand the process.
Because I have a misunderstanding : if I scan the traffik from client to server, I see that (trought the ajax call) it sends from client to server the form1, name and password (and, as MAGIC, name and password have got the value inserted by me).
So how is this possible?
Thanks to all!
That isn't magic. That's normal. Those values are entered in webbrowser. JS/Ajax has access to those values. JS/Ajax will send those values along. How else should server side/JSF know about the newly entered values?