I have h:selectBooleanCheckbox but it passes 'false' to the validator. always.
<h:panelGroup id="tncPanel">
<label>
<h:selectBooleanCheckbox id="tncSelection" value="#{businessBean.tncSelection}">
<f:validator validatorId="checkboxValidator"/>
<f:attribute name="label" value="Please agree terms and conditions."/>
</h:selectBooleanCheckbox>
I have read and agreed to all the
<a href="#" data-toggle="modal" data-target="#modal-term-and-conditions">
Terms and Conditions.
</a>
</label>
</h:panelGroup>
<h:panelGroup id="buttonPanel">
<h:commandLink id="nextButton" action="#{businessBean.goNext}">
Submit
</h:commandLink>
</h:panelGroup>
Why I have panelGroup here is, based on logic in top of page, I have a logic to display/not the button and checkbox
This is my Validator.
#FacesValidator("checkboxValidator")
public class CheckboxValidator implements Validator {
private static final String DEFAULT_LABEL = "Please confirm the address.";
#Override
public void validate(FacesContext context, UIComponent component, Object value){
String checkBoxValue = String.valueOf(((HtmlSelectBooleanCheckbox) component).getSubmittedValue());
System.out.println("checkBoxValue " + checkBoxValue);
System.out.println("value2: " + value);
String label = String.valueOf(component.getAttributes().get("label"));
if ("null".equals(label)) {
label = DEFAULT_LABEL;
}
if("false".equalsIgnoreCase(checkBoxValue)){
FacesMessage msg = new FacesMessage(null, label);
msg.setSeverity(FacesMessage.SEVERITY_ERROR);
throw new ValidatorException(msg);
}
}
}
Validator sysout always prints checkBoxValue false
UPDATE
After comment on Balusc, I add another sysout to print directly the parameter value. But still it's printing as value2: false.
There is a bug related to this situation , When you render a container that holds a from from another form you the rendered form loses its view state ,Thus form is submitted to no destination solution is to render the form container and the form its self from the other form
For example that won't work :
<h:panelGroup id="panel">
<h:form>
<h:commandButton value="Submit" rendered="#{not testAction.flag}">
<f:ajax render=":panel" listener="#{testAction.submit()}"/>
</h:commandButton>
</h:form>
<h:panelGroup id="panel">
<h:form id="secondForm" rendered="#{testAction.flag}">
<h:selectBooleanCheckbox id="checkBox" value="#{testAction.boolVal}">
<f:validator validatorId="checkboxValidator"/>
</h:selectBooleanCheckbox>
<h:commandButton value="Go" action="#{testAction.go()}"/>
</h:form>
</h:panelGroup>
Second form submit will be like this :
secondForm won't have its view state the form is submitted but with no destination on the server cuz the view object is not fetched on the server that requires the javax.faces.ViewState value to be fetched by what you have to do here is to render form as well in the f:ajax:
<f:ajax render=":panel :secondForm" listener="#{testAction.submit()}"/>
That inform server to backup the second form rendered with the javax.faces.ViewState
Refer to that post : Rendering other form by ajax causes its view state to be lost, how do I add this back? for more info
Hope that was the problem :)
Related
I am trying to log the number of the button clicks.
1. Should log the number of clicks though the form is invalid. The field value1 in the form is integer. So, It shall also consider conversion errors.
2. Action to be done at backing bean
I have tried with listener on ajax.
<h:form id="form">
<h:inputText id="in" name="in" value="#{listenBean.value1}" autocomplete="off">
</h:inputText>
<h:commandButton value="Click Me" action="#{listenBean.save}">
<f:ajax execute="#form" render="#form message eventcount" />
</h:commandButton>
<h:message for="in"/>
Button Clicks: <h:outputText id="eventcount" value="#{listenBean.eventCount}"/>
</h:form>
Bean
public void eventCount(AjaxBehaviorEvent event) {
//increment the counter
}
public void save() {
//save
}
Issues:
The listener method is not called when the conversion errors on input field binded to integer at bean. I enter the value as "some text". During thsi time listener is not called.
Version: Mojaraa 2.2.8
Is this the correct way of doing. Am I doing any mistake.
Can some one help me.
The <h:outputText value> doesn't represent a method expression which should reference a bean (listener) method. It represents a value expression which should reference a bean property which will then be outputted as (escaped) text to the response.
Your best bet is to hook on preRenderView event of the component and check if the current request represents a postback request.
<h:form id="form">
<h:commandButton ...>
<f:ajax execute="#form" render="#form" />
</h:commandButton>
Button Clicks:
<h:outputText id="eventcount" value="#{listenBean.eventCount}">
<f:event type="preRenderView" listener="#{listenBean.incrementEventCount}" />
</h:outputText>
</h:form>
private int eventCount;
public void incrementEventCount(ComponentSystemEvent event) {
if (FacesContext.getCurrentInstance().isPostback()) {
eventCount++;
}
}
public int getEventCount() {
return eventCount;
}
Note that render="#form" covers the entire form already, so there's no need of specifying individual components inside the very same form. In case you've another ajax action inside the same form for which you'd like to not count the event, then make sure that render="..." is specific enough that it doesn't cover the eventcount component.
I'm using JSF (Primefaces) in Liferay and have some problems.
I have list of people (dataTable) with Edit button for every row in dataTable. Users have property that differ one row from others, e.g. football, basketball, tennis, and every user have some of these categories. Depending on those properties, there is different page/form that needs to be filled. So, I have one ManagedBean (PendingRequest.java) that acts like dispatcher/switcher who recieves data about that person in a row and switches user to appropriate form. Form has backing bean (e.g. page signFootballer.xhtml has bean Footballer.java that have getters and setters for fields in page signFootballer.xhtml).
So, user clicks on Edit button for some row in a table, method dispatchRequest starts running and checks for category (football,...) and depending on category and initialize new object of class Footballer and sets its properties to fill form (e.g. setName("John"), etc... because it is "edit user" functionality of application).
public String dispatchRequest(Person p) {
if (p.getCategory.equals("Tennis")) {
return "NOT_OK";
} else if (p.getCategory().equals("Basketball")) {
return "NOT_OK";
} else if (p.getCategory().equals("Football")) {
Footballer f = new Footballer();
f.setName("John");
f.setLastName("Doe");
return "OK";
} else {
return "NOT_OK";
}
}
After that, I'm switching to form signFootballer.xhtml via faces-config.xml. And it goes correctly, but problem is that my form is empty.
I'm aware this isn't correct approach but I need advice, can you suggest me what is the best way how to update some row from dataTable having in mind that I need to differ rows by category and then open appropriate page and corresponding backing bean that will fill form. Because I'm not sure it is possible by using this Dispatcher class.
EDIT:
#BalusC, This is not real case, but just showing example to help you understand my problem. I have 3 different form, depending on cases for FootballPlayer, BasketballPlayer and TennisPlayer.
signFootballer.xhtml
<h:form enctype="multipart/form-data" id="form">
<div id="container">
<div class="divs">
<p style="margin-left: 22%; width:60%; font-size: 20px; font-weight: bold">Sign contract</p>
<table>
<tr>
<td>
<p:outputLabel for="name" value="First name:*" styleClass="f_text" />
<p:inputText id="name" value="#{footballer.name}" required="true" />
</td>
<td>
<p:outputLabel for="surname" value="Last name:" styleClass="f_text" />
<p:inputText id="surname" value="#{footballer.surname}" required="true" />
</td>
</tr>
</table>
</div>
<div class="submit">
<p:commandButton value="Send" id="submit" update="err_msg1 err_msg2 err_msg3" action="#{Footballer.submitForm}" styleClass="button" />
</div>
</div>
</h:form>
Footballer.java (additional variables and method are deleted)
#ManagedBean
#ViewScoped
public class Footballer {
private String name;
private String surname;
public void submitForm() {
// Validate data and save in database
}
// GETTERS AND SETTERS
pendingRequest.xhtml (it is list of request that hasn't been confirmed yet - from database)
<h:form id="form">
<h:panelGroup id="table-wrapper">
<p:dataTable id="dt" var="req" value="#{pendingRequest.requestList}">
<f:facet name="header">
Pregled prijava
</f:facet>
<p:column headerText="Id">
<h:outputText value="#{req.id}" />
</p:column>
<p:column headerText="Category">
<h:outputText value="#{req.category}" />
</p:column>
<p:column headerText="Name">
<h:outputText value="#{req.name}" />
</p:column>
<p:column headerText="Prezime">
<h:outputText value="#{req.surname}" />
</p:column>
<p:column headerText="Delete/Edit" width="10%" style="text-align:center" >
<p:commandLink immediate="true" update=":form:table-wrapper" action="#{pendingRequest.deleteRecord(p)}"/>
<p:commandLink immediate="true" action="#{pendingRequest.dispatchRequest(p)}" style="margin-left:5px;"/>
</p:column>
</p:dataTable>
</h:panelGroup>
</h:form>
PendingRequests.java (class which method is run after user choose to edit some request from a list of pending requests)
#ManagedBean
#ViewScoped
public class PendingRequest {
public List<Requests> requestList = new ArrayList<Requests>(); // "Requests" is entity class generated from database
public List<Requests> getRequestList() {
SessionFactory sessionFactory = HibernateUtil.getSessionFactory();
//save example - without transaction
Session session = sessionFactory.openSession();
session.beginTransaction();
List<Requests> tempList = session.createCriteria(Requests.class).list();
session.getTransaction().commit();
return tempList;
}
public void setRequestList(List<Requests> requestList) {
this.requestList = requestList;
}
public void deleteRecord(Requests p) {
Session session = HibernateUtil.getSessionFactory().openSession();
try {
session.beginTransaction();
session.delete(p);
session.getTransaction().commit();
} catch (HibernateException ex) {
ex.printStackTrace();
session.getTransaction().rollback();
}
}
public void dispatchRequest(Requests p) {
if (p.getCategory().equals("Football")) {
//TRANSFER ID OF THAT REQUEST TO Footballer class to populate fields in signFootball.xhtml
} else if (p.getCategory.equals("Basketball")) {
//TRANSFER ID OF THAT REQUEST TO BasketballPlayer class to populate fields in signBasketballPlayer.xhtml
} else if (p.getCategory().equals("Tennis")) {
//TRANSFER ID OF THAT REQUEST TO TennisPlayer class to populate fields in signTennisPlayer.xhtml
} else {
System.out.println("OTHER...");
}
}
Method dispatchRequests is inspecting category (football, basketball, tennis) of request and depending on it, needs to open appropriate form and fill it with values. That is the same form as for new request creation, just now it would be filled with data from database.
So, if user clicks request for Footballer it needs to pass request id probably in Footballer class constructor? Because the fields need to be set before the page is rendered?
That part of this story isn't very clear to me. I'm new to JSF and I would appreciate very much if you could give me some suggestions how to do edit funcionality?
Note: This is just an idea.
It would be sufficient to create inline dataTable editor. On edit button call bean actionListener to extract user object based on the dataTable index. Check its category and populate related class object. Then get object properties to fill fields. Render button based on the property to identify action. Call another bean actionListener on update / save button and forward data to the service layer. On successful operation show relevant message.
myBean is in request scope.
<h:form id="indexFormID">
<a4j:outputPanel ajaxRendered="true" layout="block">
<h:inputText id="inputForHD" value="#{myBean.inputParam}"></h:inputText>
<a4j:commandLink value="Submit" action="#{myBean.myMethod}" reRender="renderSuccess" process="indexFormID:inputForHD"></a4j:commandLink>
</a4j:outputPanel>
<h:panelGroup id="renderSuccess">
<h:panelGroup rendered="#{myBean.someBoolean}">
//Some other JSF components go here
</h:panelGroup>
</h:panelGroup>
</h:form>
MyBean class definition:
private String inputParam;
//Getters and setters are there
public String myMethod()
{
log.debug("~ Value of inputParam" +this.getInputParam()); //This is printing null value for inputParam
//when commandLink is clicked
return null;
}
Why my inputParam is not getting set with the input parameters?
Ok I found few issues with your approach:
<h:inputText id="inputForHD" value="#{myBean.inputParam}"></h:inputText>
You are already mapping the inputParam attribute with this bean, why have a new Id "inputForHD"
Use the inputParam itself, if you want to use inputForHD, you can pick the same from request Parameter map like.
String inputForHD = FacesContext.getCurrentInstance().getExternalContext().getRequestParameterMap().get("indexFormID:inputForHD");
Also as I mentioned previously wrap the output panel inside the and a4j panel e.g.
<h:panelGroup id="renderSuccess">
<h:panelGroup rendered="#{helloWorld.someBoolean}">
//Some other JSF components go here
<h:inputText id="inputForHDasdasd" value="#{helloWorld.inputParam}"></h:inputText>
</h:panelGroup>
</h:panelGroup>
This is working fine, let know if any issues.
I have a JSF view with a Primefaces data table and a command button insite it, as fallows:
<p:messages id="statusMessages" showDetail="true" />
<h:form id="listForm">
<p:panel header="Wellsite List">
<br />
<h:outputLabel value="Welcome, #{wellsiteController.loggedUser.login}" />
<br />
<br />
<p:dataTable id="dataTable" var="wellsite" value="#{wellsiteController.wellsiteDataTableModel}"
paginator="true" rows="10" selection="#{wellsiteController.wellsite}">
<p:column selectionMode="single" style="width:18px" id="radioSelect" />
<p:column sortBy="#{wellsite.reference}" headerText="Wellsite ID">
<h:outputText value="#{wellsite.reference}" />
</p:column>
<p:column headerText="Allowed Groups">
<h:outputText value="#{wellsite.allowedGroups.toString()}" />
</p:column>
<f:facet name="footer">
<h:panelGrid columns="3">
<p:commandButton id="addWellsite" value="Add New Wellsite" icon="ui-icon-flag" ajax="false" action="#{wellsiteController.showAddWellsite}"/>
<p:commandButton id="editWellsite" value="Edit Selected Wellsite" icon="ui-icon-wrench" ajax="false" action="#{wellsiteController.showEditWellsite}"/>
<p:commandButton id="deleteWellsiteButton" value="Remove Selected Wellsite" icon="ui-icon-trash" onclick="confirmation.show()" type="button"/>
</h:panelGrid>
</f:facet>
</p:dataTable>
<p:spacer height="20" />
</p:panel>
<p:confirmDialog id="confirmDialog" message="Are you sure you want to remove the selected Wellsite along with all it's data?" header="Confirmation" severity="alert" widgetVar="confirmation">
<p:commandButton id="confirm" value="Yes" ajax="false" oncomplete="confirmation.hide()" action="#{wellsiteController.deleteWellsite}" />
<p:commandButton id="decline" value="Cancel" onclick="confirmation.hide()" type="button" />
</p:confirmDialog>
</h:form>
And here's the controller:
#ManagedBean(name = "wellsiteController")
#RequestScoped
public class WellsiteController implements Serializable {
private static final long serialVersionUID = 1L;
#ManagedProperty("#{wellsiteDao}")
private WellsiteDao wellsiteDao;
#ManagedProperty("#{userDao}")
private UserDao userDao;
#ManagedProperty("#{groupDao}")
private GroupDao groupDao;
#ManagedProperty("#{userController.loggedUser}")
private UserEnt loggedUser;
private WellsiteEnt wellsite;
private List<WellsiteEnt> wellsiteList;
DualListModel<GroupEnt> pickGroupsModel;
public WellsiteController(){
}
#PostConstruct
public void build(){
wellsite = new WellsiteEnt();
wellsite.setAllowedGroups(new ArrayList<GroupEnt>());
}
/*some getters & setters*/
public WellsiteDataTableModel getWellsiteDataTableModel(){
return new WellsiteDataTableModel(getWellsiteList());
}
public void setPickGroupsModel(DualListModel<GroupEnt> model){
pickGroupsModel = model;
}
public DualListModel<GroupEnt> getPickGroupsModel() {
if(pickGroupsModel == null){
List<GroupEnt> allGroups = groupDao.getAll();
List<GroupEnt> currentGroups = wellsite.getAllowedGroups();
for(GroupEnt g : currentGroups){
allGroups.remove(g);
}
pickGroupsModel = new DualListModel<GroupEnt>(allGroups, currentGroups);
}
return pickGroupsModel;
}
public String listWellsites(){
getWellsiteList();
return "listWellsites";
}
public String showAddWellsite(){
FacesContext context = FacesContext.getCurrentInstance();
setWellsite(new WellsiteEnt());
wellsite.setAllowedGroups(new ArrayList<GroupEnt>());
pickGroupsModel = null;
context.addMessage(null, new FacesMessage(FacesMessage.SEVERITY_INFO,
"Fields annotated with a ' * ' are mandatory",""));
return "addWellsite";
}
public String addWellsite(){
FacesContext context = FacesContext.getCurrentInstance();
wellsite.setDate(new Date());
wellsite.setLastUpdate(wellsite.getDate());
try {
wellsiteDao.addWell(wellsite);
for(GroupEnt g : pickGroupsModel.getTarget()){
GroupEnt group = groupDao.getOne(g.getGroupId());
group.getGroupWellsites().add(wellsite);
groupDao.update(group);
}
return listWellsites();
} catch (Exception ex) {
Logger.getLogger(WellsiteController.class.getName()).log(Level.SEVERE, null, ex);
context.addMessage(null, new FacesMessage(FacesMessage.SEVERITY_ERROR,
ex.getMessage(),""));
return null;
}
}
}
This view gets rendered correctly. The datatable and buttons looks fine. The problem is that when first i click the "addWellsite" commandButton, nothing happens. The page just seems to refresh. If i click it again, as exception happens:
java.lang.NumberFormatException: For input string: "null"
Using a debugger, i found out that the "addWellsite"'s action is NOT called the first time, and so, not outcome is generated (thus, the page refresh).
The exception is probably comming from the lack of initialization in the current or the target views (since both view are displayed from action methods that were not called in the page refresh)
The question is: WHY the action method is not called the first time?
As from this answer:
Whenever an UICommand component fails to invoke the associated action, verify the following:
UICommand components must be placed inside an UIForm component (e.g. h:form).
I do have a h:form
You cannot nest multiple UIForm components in each other (watch out with include files!).
There's only one.
No validation/conversion error should have been occurred (use h:messages to get them all).
I have a h:messages that does not display any error.
If UICommand components are placed inside an UIData component, ensure that exactly the same DataModel (the object behind the UIData's value attribute) is preserved.
The commandButton is inside the dataTable, but the target view does not need the dataModel. As my controller code shows, the object is built as the view tries to retrive it. The next request is not using this dataTable, to i do not handle it anymore.
The rendered and disabled attributes of the component and all of the parent components should not evaluate to false during apply request values phase.
There's no rendered or disbled attributes.
Be sure that no PhaseListener or any EventListener in the request-response chain has changed the JSF lifecycle to skip the invoke action phase.
No phaseListener is defined.
Be sure that no Filter or Servlet in the same request-response chain has blocked the request fo the FacesServlet somehow.
No other Servlet is defined. I don't even know what a Filter is.
WHY the action method is not called the first time?
This can happen when a parent of this <h:form> was been rendered by an ajax request initiated by another <h:form> beforehand. The rendered/updated <h:form> would then lose its view state. This is caused by a bug in the JavaScript API as described in JSF issue 790 which is already fixed for the shortly upcoming JSF 2.2.
In the meanwhile, with JSF 2.0/2.1, you need to explicltly specify the client ID of the <h:form> in the render (or for PrimeFaces, the update) attribute of the action in the other form.
E.g.
<h:commandButton ...>
<f:ajax ... render=":listForm" />
</h:commandButton>
or
<p:commandButton ... update=":listForm" />
Or just make it a normal (non-ajax) request instead.
See also:
Communication in JSF 2 - Ajax rendering of content which contains another form
I have a form with a dataTable which has various columns having links and outputTexts. There is one input field which is evaluated through an ajax request . A custom validator makes sure that only integers are added to the field. The form is below.
<form>
<h:dataTable var="item" value="#{listItems.model}" id="adminlistItems">
//other columns having commandLinks and outputTexts
<h:column>
<f:facet name="header" >
<h:outputText value="Quantity"/>
</f:facet>
<f:ajax listener="#{listItems.AddQuantityAction}">
<div style="padding:5px;float:left">
<h:inputText label="changeQuantity" id="addquantity" value="#{item.additionalQuantity}" maxlength="4" size="3">
<f:validator validatorId="integerValidator"/>
</h:inputText>
<h:outputText value=" "/>
<h:commandButton value="AddQuantity" />
<h:message for="addquantity"/>
</div>
</f:ajax>
</h:column>
</h:dataTable>
</h:form>
The code for the bean is :
#ViewScoped
#ManagedBean
public class ListItems implements Serializable {
//...
public String AddQuantityAction(){
//...
boolean result = //some action
FacesContext context=FacesContext.getCurrentInstance();
UIComponent component=UIComponent.getCurrentComponent(context);
String clientID=component.getClientId(context);
if (result) {
FacesMessage message = new FacesMessage("Quantity added successfully");
FacesContext.getCurrentInstance().addMessage(clientID, message);
} else {
FacesMessage message = new FacesMessage("Quantity not added.Processing error");
FacesContext.getCurrentInstance().addMessage(clientID, message);
}
return "adminListItems";
}
}
The custom validator throws a validator exception which is not displayed. And the listener also has code for messages which too are not displayed. I have read several similar questions and this sounds a common question too. But even if i am missing something obvious,i am in need of a third eye to see what i dont.
The execute and render of <f:ajax> defaults to #this. So only the currently active component will be processed and refreshed. When you press the button, this won't send the input value nor refresh the message component.
Fix it accordingly:
<f:ajax execute="addquantity" render="addquantity_message" listener="#{listItems.AddQuantityAction}">
...
<h:message id="addquantity_message" for="addquantity"/>
...
</f:ajax>
By the way, why don't you just use the builtin javax.faces.Integer converter instead of that validator?
<h:inputText ... converter="javax.faces.Integer">
Further, the return value of ajax listener methods should be void. It's totally ignored in any way. Also, method names should start with lowercase. See also Java naming conventions.
Update as per the comment, that didn't seem to work out well with regard to validation. The listener is invoked 2 times because essentially 2 ajax requests are been sent, one for the input and one for the command. I suggest to move the listener method to the <h:commandButton action>.
<f:ajax execute="addquantity" render="addquantity_message">
...
<h:commandButton action="#{listItems.AddQuantityAction}" />
<h:message id="addquantity_message" for="addquantity"/>
</f:ajax>
You'll only fix the obtained client ID to be the input ID, not the button ID.