How to access the bean linked in an attribute of UIComponent? - java

I need to access the bean object used in a EL expression of an UIComponent.
For example, in this sample code:
xhtml:
<h:form>
<f:view>
<p:selectBooleanButton value="#{baseBean.selected}" onLabel="Instalar" offLabel="Ignorar" onIcon="ui-icon-check" offIcon="ui-icon-close">
<f:validator validatorId="baseValidator.items" />
</p:selectBooleanButton>
<p:commandButton type="submit" value="Submit"
actionListener="#{baseBean.process}"
ajax="false" />
</f:view>
</h:form>
java:
#FacesValidator("baseValidator.items")
public static class BaseValidator implements Validator
{
#Override
public void validate(FacesContext context, UIComponent component,
Object value) throws ValidatorException {
ValueReference reference = component.getValueExpression("value").getValueReference(context.getELContext());
Object o1 = reference.getBase();
Object o2 = reference.getProperty();
return; //break point here
}
}
When the command button is pressed the BaseValidator.validate is executed, I need to get the baseBean object used in <p:selectBooleanButton value="#{baseBean.selected}">
My code is currently throwing NullPointerException because getValueReference is returning null. How do I get that object inside the validate method?

value="#{baseBean.selected}" should be changed as "#{baseBean.value}"

Related

How do I register the PrimeFaces ClientValidator in my web application?

my question is how do i register my custom EmailValidator so that p:clientValidator will be able to use my custom EmailValidator on validating my p:inputText? I implemented ClientValidator interface from org.primefaces.validate.ClientValidator but my custom validator is still not being used by the code.
My code is shown below.
EmailValidator.java
#FacesValidator("emailValidator")
public class EmailValidator implements Validator, ClientValidator {
private Pattern pattern;
private static final String EMAIL_PATTERN = "^[\\w-\\+]+(\\.[\\w]+)*#[\\w-]+(\\.[\\w]+)*(\\.[a-z]{2,})$";
public EmailValidator() {
pattern = Pattern.compile(EMAIL_PATTERN);
}
#Override
public void validate(FacesContext context, UIComponent component, Object value) throws ValidatorException {
if(!pattern.matcher(value.toString()).matches()) {
throw new ValidatorException(new FacesMessage(FacesMessage.SEVERITY_ERROR, null, "Invalid Email format."));
} else {
// Code to check if email already exists in the database.
// 'email exists' is only a pseudocode.
if (email exists) {
throw new ValidatorException(new FacesMessage(FacesMessage.SEVERITY_ERROR, null, "Email already exists in database."));
}
}
}
#Override
public Map<String, Object> getMetadata() { return null; }
#Override
public String getValidatorId() { return "emailValidator"; }
}
index.xhtml (example filename only):
... (other code)
<h:outputText value="Email"/> <span class="required-asterisk">*</span>
<p:inputText id="studentEmail" value="#{StudentAdd.student.email}"
required="true" styleClass="form-input-fields"
requiredMessage="Required.">
<!-- I want these two to work. -->
<f:validator for="studentEmail" validatorId="emailValidator"/>
<p:clientValidator event="blur"/>
<!-- I used this code before but whenever I submit the form the error message disappears so I don't use this code.-->
<!-- <p:ajax update="studentEmail,studentEmailMsg" event="blur"/> -->
</p:inputText>
<p:message id="studentEmailMsg" for="studentEmail"/>
... (other code)
<p:commandButton id="saveUserInfo" value="Next" ajax="true" validateClient="true" partialSubmit="true" process="#this,...,studentEmail"/>
NOTE: I already added the context-param primefaces.CLIENT_SIDE_VALIDATION to true in my web.xml.
NOTE: I'm using JSF 2.2.16 Mojarra and primefaces-6.2.RC2.
NOTE: Changing ajax to false of commandButton will solve the problem but I want it to be ajax.
Make sure you have implemented js counterpart of emailvalidator.
Refer script section in primefaces showcase.
https://www.primefaces.org/showcase/ui/csv/custom.xhtml

JSF with gettable only

I'm trying to achieve a chat system through JSF. All text typed inside h:inputText will be stored after h:commandButton is pressed. After this, I have a table to print all data typed so far. This way, I have the following code for JSF:
<h:form>
<h:inputText id="id1" value="#{unicoBean.text}" />
<h:commandButton id="botao" value="Entrar" action="#{unicoBean.test}"
onclick="test()"
/>
</h:form>
<h:dataTable value="#{unicoBean.all}" var="msg">
<h:column>
#{msg.text}
</h:column>
</h:dataTable>
<script>
function test() {
alert("alert");
}
</script>
And this for backbean:
#ManagedBean
public class UnicoBean {
Facade f = new Facade();
public void setText(String s) throws Exception {
f.setText(s);
}
public List<Message> getAll() throws Exception {
return f.getAll();
}
public void test() {
System.out.println("bean called on jsf");
}
}
Inside h:inputText I want only to set values, not get them and throw back to html. Unfortunately, JSF says "Expression is not gettable", even when I don't want to get anything, only set, as exposed on my Bean. How I solve this?
It's not possible to achieve this using getter/setter strategy because is not part of JSF but Expression Language (EL). JSF only uses it to bind the data of the HTML components to the fields of a bean through proper getters and setters
However, you can use binding attribute via UIInput to pass the input field value as an argument to your action button:
<h:form>
<h:inputText id="id1" binding="#{input1}" />
<h:commandButton id="botao" value="Entrar" action="#{unicoBean.test(input1.value)}"
onclick="test()" />
</h:form>
And then receive the new value from your action method:
public void test(String value) {
System.out.println("bean called on jsf: " + value);
}

<c:forEach> and <h:commandLink> not able to send param to function

I can't get the h:command to send param to the function
the cat1 has values AR array but I can't get it to send the param in the correct param
JSP code
<c:forEach items="${categoryBean.getSubCategoryByID(0)}" var="cat" varStatus="stat">
<c:set var="cat1" scope="request" value="${cat}"/>
<li>
<c:out value="${cat1.id}" /> <c:out value="${cat1.name}" />
<h:commandLink id="goprime" action="#{categoryBean.gotoPrimecat}" value="#{cat1.name}">
<f:setPropertyActionListener target="#{categoryBean.CatID}" value="#{cat1.id}" />
</h:commandLink>
</li>
</c:forEach>
the bean code
public String getCatID() {
return CatID;
}
public void setCatID(String CatID) throws SQLException, ClassNotFoundException {
logger.info("in setter: "+CatID);
this.CatID = CatID;
//products = product.searchProductsByCategory(null, null, CatID);
}
public void GotoPrimecat() throws IOException {
logger.info("in primercat , id: "+this.CatID);
ExternalContext context = FacesContext.getCurrentInstance().getExternalContext();
context.redirect("category.jsp");
return;
}
Looks like the problem is the name of your method. In your page the method is referenced as categoryBean.gotoPrimecat, while in your bean the method is GotoPrimecat(). Make sure the method name is exactly the same, including the case, and it should be ok. In this case your bean method should begin with a lowercase letter, which is the generally accepted style anyway.

Java JSF About Custom Validation

i am using this way in custom validation i am little bit confused if this way is correct or not if i assumed that i have this form:
<h:form id="myForm>
<h:outputText value="user name" />
<h:inputText value="#userBean.userName" id="userName" />
<h:outputText value="Password" />
<h:inputText value="#userBean.Password" id="passwd" />
</h:form>
and i have its Managed Bean :
#ManagedBean(name="userBean")
#SessionScoped
public class UserBeanData{
private String userName;
private String password;
// with setters and getters........
//
}
and the custom validator to validate the Managed Bean field and the Implmentation like :
#Override
public validate(FacesContext context, UIComponent component, Object value) throws ValidatorException{
Map<String, String> params = context.getExternalContext().getRequestParametersMap();
String username = params.get("myForm:username");
String pass = params.get("myForm:passwd");
// validate : if fields are not null check if the user exists if the result is empty , throws a validation Message Error
}
My Question is : Retrieving the Managed bean values like this is true or not ????
You're basically looking for the solution in the wrong direction. Validation is only applicable on the individual submitted values, e.g. minimum/maximum length, non-empty/null, regex pattern, etcetera. But you want to invoke a business action based on all submitted values: logging-in an user. This is not exactly input validation.
Just add required="true" to the both input components and perform the job in the action method.
E.g.
<h:form id="myForm>
<h:outputText value="user name" />
<h:inputText value="#{userBean.userName}" id="userName" />
<h:message for="userName" />
<h:outputText value="Password" />
<h:inputSecret value="#{userBean.password}" id="passwd" />
<h:message for="passwd" />
<h:commandButton value="Login" action="#{userBean.login}" />
<h:messages globalOnly="true" />
</h:form>
with
#ManagedBean
#RequestScoped
public class UserBean {
private String userName;
private String password;
#EJB
private UserService service;
public String login() {
User user = service.find(userName, password);
if (user != null) {
FacesContext.getCurrentInstance().getExternalContext().getSessionMap("user", user);
return "home?faces-redirect=true";
} else {
FacesContext.getCurrentInstance().addMessage(null, new FacesMessage("Unknown login"));
return null;
}
}
// ...
}
Pay attention to the validate method's firm. It has an UIComponent parameter that is the component validated by the method. This UIComponent has both the current value (getValue()) and the value that the user submitted (getSubmittedValue()).
You might have to cast that UIComponent to the particular type of component you're validating (int this case, it's an UIInput).
Now, if you're going to validate both username and password prior to a log in, there are several ways to do it. In your case, validating the username field with the password field as an added parameter should suffice. You can achieve that by doing this:
<h:outputText value="user name" />
<h:inputText value="#userBean.userName" id="userName" validator="#{yourBean.validateLogin}">
<f:attribute name="pass" value="#{passwordField}" />
</h:inputText>
<h:outputText value="Password" />
<h:inputText value="#userBean.Password" id="passwd" binding="#{passwordField}"/>
Note that the binding in the password <h:inputText/> is related to the value of the pass of the <f:attribute/> tag nested in your username <h:inputText/>. With this setup, you can perform your validation like this:
public void validateLogin(FacesContext context, UIComponent component, Object value) throws ValidatorException {
//I suppose it's a typo, but your validate method lacks the return type.
String username = (String) value;
UIInput passwordInput = component.getAttributes().containsKey("pass") ?
(UIInput) component.getAttributes().get("pass") : null;
if(passwordInput != null) {
//Just to be sure the input was added as a parameter successfuly
String submittedPassword = passwordInput.getSubmittedValue();
//Now, do your validations based on the strings "username"
//and "password".
}
}
Since all of this is being done in the validation phase, the values aren't set in your managed bean yet, that's why you have to play around a little with the submitted values.

Primefaces p:menuitem pass an attributes to actionListener

I would like to pass some attributes to actionListener method.
My implementation is like...
<c:forEach items="${customerProductsBean.userProductList}" var="userProduct">
<p:panel toggleable="#{true}" toggleSpeed="500" header="#{userProduct.product}" >
// Some Code... Data Table and Tree Table
<f:facet name="options">
<p:menu>
<p:menuitem value="ProductSetup" actionListener="#{customerProductsBean.getProductSetupData}" >
<f:attribute name="userIdParam" value="#{data.userId}"/>
<f:attribute name="geCustomerIdParam" value="#{data.geCustomerId}"/>
<f:attribute name="acpProductParam" value="#{data.acpProduct}"/>
</p:menuitem>
<p:menuitem value="Remove Product" url="#" onclick=""/>
</p:menu>
</f:facet>
</p:panel>
</c:forEach>
And in Java Action Listener
public void getProductSetupData(ActionEvent actionEvent) {
try {
String userIdParam =
(String)actionEvent.getComponent().getAttributes().get("userIdParam");
String geCustomerIdParam =
(String)actionEvent.getComponent().getAttributes().get("geCustomerIdParam");
String acpProductParam =
(String)actionEvent.getComponent().getAttributes().get("acpProductParam");
} catch(Exception e) {
// Exception
}
}
I tried it using <f:attribute> and <f:param> but was not able to get the value in Java.
In java It shows null for each value.
This won't work if #{data} refers to the iterating variable of an iterating JSF component such as <h:dataTable var>. The <f:attribute> is set during JSF view build time, not during JSF view render time. However, the <h:dataTable var> is not available during view build time, it is only available during view render time.
If your environment supports EL 2.2, do instead
<p:menuitem ... actionListener="#{customerProductsBean.getProductSetupData(data)}" />
with
public void getProductSetupData(Data data) {
// ...
}
Or if your environment doesn't, do instead
public void getProductSetupData(ActionEvent event) {
FacesContext context = FacesContext.getCurrentInstance();
Data data = context.getApplication().evaluateExpressionGet(context, "#{data}", Data.class);
// ...
}

Categories

Resources