How to use ajax with Primefaces components programmatically - jsf

I'm trying to create Primefaces UIComponents programmatically and somehow I'm not able to get the data to the Backing Bean. Not sure if it's the Ajax or the value I set for the InputText.
My code that I want to write programmatically:
<p:inputText id="id_test" value="#{myBean.value}">
<p:ajax />
</p:inputText>
This is how I tried to solve the problem:
private String value; // Getter&Setter
public void buildComponent(){
FacesContext fc = FacesContext.getCurrentInstance();
Application ap = fc.getApplication();
InputText inputText = (InputText) ap.createComponent(fc, "org.primefaces.component.InputText", "org.primefaces.component.InputTextRenderer")
inputText.setValue(value);
inputText.setId("id_test");
AjaxBehavior ajaxBehavior = (AjaxBehavior) ap.createBehavior(AjaxBehavior.BEHAVIOR_ID);
inputText.addClientBehavior(inputText.getDefaultEventName(), behavior);
}

You will need to create a ValueExpression that resolves to your bean property. How else should your dynamic input know where to send input values to?
Instead of:
inputText.setValue(value);
Do this:
ExpressionFactory expressionFactory = FacesContext.getCurrentInstance()
.getApplication().getExpressionFactory();
ValueExpression veBinding = expressionFactory.createValueExpression("#{myBean.value}", String.class);
inputText.setValueExpression("value", veBinding);

I'm not sure what you intend to do, but it might be better to render the component dynamically instead of creating it. Something like that:
<p:inputText id="id_test" value="#{myBean.value}" rendered="#{myBean.isSomeCondition">
<p:ajax />
</p:inputText>
or
<p:inputText id="id_test" value="#{myBean.value}" rendered="#{myBean.value != 'whatever'">
<p:ajax />
</p:inputText>

Related

How to pass the selected values from selectcheckBoxMenu to my bean?

I'm using JSF 2.2.8 and primefaces 6.0, and i have a selectCheckBoxMenu i want to retrieve the selected values in my bean.
The selectCheckboxMenu is filled from the database but when i select the attributes and I save nothing happens it does not call the save function
Here is my selectCheckBoxMenu
<p:outputLabel for="ressource" value="Ressource"/>
<h:panelGroup >
<p:selectCheckboxMenu id="ressource" label="Ressource" value="#{affectationBean.selectedRessource}" multiple="true">
<f:selectItems value="#{affectationBean.ressources}" var="r" itemLabel="#{r.nom}" itemValue="r.idt_ressource" />
</p:selectCheckboxMenu>
</h:panelGroup>
<p:commandButton icon="ui-icon-save" actionListener="#{affectationBean.save}" value="Save" update="#affectation" ajax="false" style="display:inline-block;margin-top:5px"/>
Here is the the declaration of the selectedRessource and the actionListener save
private Long [] selectedRessource;
// Getters setters and Construct
public void save(){
for(int i=0 ;i<selectedRessource.length;i++){
system.out.println("id ===> " + selectedRessource[i]);
}
My suggestion would be:
First make sure everything is inside the h:form tag.
don't need to multiple = true as this tag does not take this attribute
i tested with below modification and got the selected multiple value in my bean. The only difference is i am using same value for itemLabel and itemValue but in your case it is object. i am using primefaces 6 also and dont even need to change actionListner to action. It is working as it is.sample xhtml
sample ResourceBean.java
<p:outputLabel for="ressource" value="Ressource"/>
<h:panelGroup >
<p:selectCheckboxMenu id="ressource" label="Ressource" value="#{resourceBean.selectedRessource}">
<f:selectItems value="#{resourceBean.ressources}" var="r" itemLabel="#{r}" itemValue="#{r}" />
</p:selectCheckboxMenu>
</h:panelGroup>
<p:commandButton icon="ui-icon-save" actionListener="#{resourceBean.save}" value="Save" ajax="false" style="display:inline-block;margin-top:5px"/>
The problem is in your p:commandButton, you have 3 options
change your method:
public void save(ActionEvent actionEvent){...}
change your action listener value:
actionListener="#{affectationBean.save()}"
or change your button to use action
action="#{affectationBean.save}"
DISCLAIMER: This is a workaround. It is not intended to be a permanent solution but will allow you to use selectCheckboxMenu and keep working.
There is an issue with this component that prevents it from passing values to the backing bean upon submit.
For some reason the array that should contain the selected values gets cleared out upon submit. Therefore I made an extra array that I did not declare in the tag, and updated in on every change event. Then on submit the values were still there. See below:
BackingBean.java
private String[] sCodes;
private String[] sCodes2; //extra array, not in form.xhtml
public void updateCodes()
{
sCodes2 = sCodes; //keeps the values in the other array
}
public void doSend() throws IOException
{
log.trace("selected codes: {} selected codes2 length: {}", sCodes.length, sCodes2.length);
}
form.xhtml
<p:selectCheckboxMenu id="codeCtl" value="#{bean.SCodes}" label="Codes" filter="true" filterMatchMode="startsWith" panelStyle="width:250px">
<f:selectItems value="#{bean.menuCodes}" />
<p:ajax event="change" listener="#{bean.updateCodes()}" />
</p:selectCheckboxMenu>
<p:commandButton value="submit" actionListener="#{bean.doSend}" id="ctlSubmit" update="appform"/>

How to skip validation phase in p:ajax

I bumped into that problem today at work. To make long story short I want to skip validation phase (in fact also not check required attribute) while using p:ajax component, though I want to update model in bean.
To illustrate the problem:
View:
<h:form>
<p:messages id="msg" />
<p:selectBooleanCheckbox value="#{bean.flag}">
<p:ajax listener="#{bean.flagChanged}" update="#form" />
</p:selectBooleanCheckbox>
<p:inputText value="#{bean.value}" required="true"
disabled="#{bean.flag}" validator="#{bean.validate}">
<p:ajax event="keyup" update="msg" />
</p:inputText>
<p:commandButton />
</h:form>
Bean:
public class Bean {
private Integer value;
private Integer prevValue;
private boolean flag;
public void flagChanged() {
if (!flag) {
value = prevValue;
} else {
prevValue = value;
value = null;
}
}
// value and flag setters and getters
public void validate(FacesContext facesContext, UIComponent uiComponent, Object value) {
Integer number = (Integer) value;
if (number == 7) {
throw new ValidatorException(new FacesMessage(FacesMessage.SEVERITY_ERROR, "7 is my lucky number", ""));
}
}
}
Checkbox is to disable and enable input text simultaneously hiding value when it is disabled and restoring it when it is enabled. Problem occures when user fills wrong value that is validated immediately and therefore not updated into the bean. So after clicking and unclicking checkbox previous correct value is restored. The very same situation happens while deleting previous value and leaving blank field (required is set to true and hence again previous value is restored).
I tried to set immediate=true, but that changes nothing, so I'm wondering if there is any way to skip validation phase in p:ajax. Maybe I am trying to achieve this in not exactly proper way (any hints appreciated!), but I would like to know if that approach is somehow possible to accomplish.
I thought there is built-in solution that solves that problem. As no one seems to exist I present my workaround to this problem (although it's not really answer to my question, becouse validation is still processed, I just ignore validation in my own validator).
<h:form>
<p:messages id="msg" />
<p:selectBooleanCheckbox value="#{bean.flag}">
<p:ajax listener="#{bean.flagChanged}" update="#form" />
</p:selectBooleanCheckbox>
<p:inputText value="#{bean.value}"
required="#{not empty param[submitButton.clientId]}" disabled="#{bean.flag}"
validator="#{bean.validate}">
<p:ajax event="keyup" update="msg" />
</p:inputText>
<p:commandButton action="#{bean.submit}" update="#form" binding="#{submitButton}">
<f:param name="validate" value="true" />
</p:commandButton>
</h:form>
Validation method:
public void validate(FacesContext facesContext, UIComponent uiComponent, Object value) {
Map<String, String> params = FacesContext.getCurrentInstance().getExternalContext().getRequestParameterMap();
if (!params.containsKey("validate")) {
return;
}
Integer number = (Integer) value;
if (number == 7) {
throw new ValidatorException(new FacesMessage(FacesMessage.SEVERITY_ERROR, "7 is my lucky number", ""));
}
}
One way I can think of is to use <p:commandButton> with ajax="false" to submit the form. In addition, in your validator method, add the following line to check for ajax submission of the value:
if (FacesContext.getCurrentInstance().isPostback()) return;
In this case, using immediate="true" in <p:ajax> does not help because the <p:inputText> component will still be converted and validated as usual. The only difference is that it would go through this process earlier than other components on the page. Hope this helps :)

Add selectedValue from selectonemenu to list

So, here's the deal:
I have a selectOneMenu in my view:
<p:selectOneMenu value="#{personBean.person.personStates.state}" id="estadoRg"
converter="entityConverter">
<f:selectItems value="#{stateBean.states}" var="state"
itemLabel=#{state.name}" itemValue="#{state}">
</f:selectItems>
</p:selectOneMenu>
Where personStates is a list containing person, state n date.
Is it possible to add the value from the itemValue directly to the personStates list? (I have a addPersonState method autobuilt in my PersonModel)
If not, how should I do this?
I don't want to add one state instance for each selectOneMenu (will be 5) in my personBean...
Was it clear?
You should handle it via selectedState value and then you can bind it for specific person:
<p:selectOneMenu value="#{stateBean.selectedState}" id="estadoRg"
converter="entityConverter">
<f:selectItems value="#{stateBean.states}" var="state"
itemLabel=#{state.name}" itemValue="#{state}">
</f:selectItems>
</p:selectOneMenu>
This is the way how p:selectOneMenu is used, to be able to bind selected state and the person call a method:
<p:commandButton actionListener="#{personBean.matchStates}" />
And backing bean method:
public void matchStates {
FacesContext facesContext = FacesContext.getCurrentInstance();
ElContext elContext = facesContext.getELContext();
Object stateBean = elContext.getELResolver().getValue(elContext, null, "stateBean").
State selectedState = stateBean.getSelectedState();
personList.get(index).setState = selectedState;
}

How to pass second value in JSF validator?

I have a simple JSF input form into edit page and Validator which checks the value for duplication:
<td>Name</td>
<td>
<h:outputText value="#{ud.name}"
rendered="#{not DCProfileTabGeneralController.editable}" />
<h:inputText id="dcname" value="#{ud.name}" rendered="#{DCProfileTabGeneralController.editable}"
validator="#{ValidatorDatacenterController.validateDatacenterName}" autocomplete="off">
<f:ajax event="blur" render="dcnamevalidator" />
</h:inputText>
<h:message id="dcnamevalidator" for="dcname" />
</td>
public void validateDatacenterName(FacesContext context, UIComponent component, Object value){
....
}
I'm interested is there any possible way to send a second value which will be used into the validation process?
<f:attribute> comes to mind. Add one to the inputtext and retrieve it in the validator.
<h:inputText id="dcname".....
<f:attribute name="param" value="myparam" />
</h:inputText>
And:
String param = (String) component.getAttributes().get("param");
Can get the value from EL. Good luck
You can add a postValidate event to validate multiple fields , like
<f:event listener="#{bean.validationMethod}" type="postValidate" />
this should fire before model updates and you can get the new value for different component with
FacesContext fc = FacesContext.getCurrentInstance();
UIComponent components = event.getComponent();
UIInput param1 = (UIInput) components.findComponent("param1");
UIInput param2 = (UIInput) components.findComponent("param2");
If the validation fails , call the FacesContext renderResponse method to skip model update.

how to send parameters to properties file if i use attribute requiredMessage of inputText

In jsf according to what I read I can replace parameters in a resource bundle string using
<h:outputFormat value="#{msg['message.param2']}">
<f:param value="param0" />
<f:param value="param1" />
</h:outputFormat>
My problem is I am working with a primefaces tag and I need to use the attribute requiredMessage of inputText, similar to this:
<p:inputText value="#{cteYDetalleMb.cteEnCaptura.nombreComercial}" style="width: 50em" required="true"
requiredMessage="#{msg['validacion.datosRequeridos']}" />
My message to validacion.datosRequeridos is requiring a parameter and the example working above is different. How can i resolve this, i try to use <f:param> but it does not work.
Your best bet is creating a custom EL function so that you can end up like follows:
<p:inputText ... requiredMessage="#{my:format(msg['validacion.datosRequeridos'], 'param0', 'param1')}" />
You could also create a custom UI component which extends <h:outputFormat> and captures the output and stores it in a variable in the EL scope:
<my:outputFormat value="#{msg['message.param2']}" var="requiredMessage">
<f:param value="param0" />
<f:param value="param1" />
</my:outputFormat>
<p:inputText ... requiredMessage="#{requiredMessage}" />
Both approaches are available in JSF utility library OmniFaces in flavor of of:format2() and <o:outputFormat> respectively.
Not the best solution but You can override all default required message with this line: javax.faces.component.UIInput.REQUIRED = new required message. label:{0}
The parameter is the label attribute of the inputText.
Or you can create a backingbean method. It reads the message from the bundle.
<p:inputText value="#{cteYDetalleMb.cteEnCaptura.nombreComercial}" style="width: 50em" required="true" requiredMessage="#{controller.getRequiredMessage(param)}"/>
You can use these helper methods to reading messages from the controllers.
public static String getMessage(String key) {
FacesContext fc = FacesContext.getCurrentInstance();
String mb = fc.getApplication().getMessageBundle();
ResourceBundle resourceBundle = ResourceBundle.getBundle(mb, fc.getViewRoot().getLocale());
return resourceBundle.getString(key);
}
public static String getMessage(String key, String params[]) {
MessageFormat messageFormat = new MessageFormat(getMessage(key), FacesContext.getCurrentInstance().getViewRoot().getLocale());
return messageFormat.format(params);
}

Resources