How to dynamically refresh h:selectManyCheckbox selectItems - jsf

I am trying to implement a scenario using JSF. I have a commandExButton and when user click this button "A" it shows the panelDialog which contains the selectManyCheckBox items. I generat these items in the backend bean by parsing one file which is continuously getting updated. What I want is, whenever I click this button "A" I should get the latest selectItems by parsing the file through the backend bean. But what I get it the same selectItem which was generated when page rendered first time. So as of now I have a workaround, in which I included one refresh button which actually refresh the page and then user click "A" to get the latest selectItem by parsing the current file's content. But is it doable in anyway without adding new button and using the existing button?
Following is the code which I am using
<td>
<hx:commandExButton id="preferenceButton" styleClass="form" value="#{nls.preferenceLink}"
title="#{nls.preferenceLinkTitle}" type="submit" />
</td>
<td>
<h:form id="PrefForm" rendered="#{Test.isCurrent}">
<hx:panelDialog type="modal" id="preferenceSet" styleClass="panelDialog" for="preferenceButton"
title="#{nls.preferenceDialogTitle}">
<h:outputText styleClass="panelStartMessage" style="display:block;"
value="#{nls.preferenceDialogWindowText}" />
<h:panelGroup rendered="#{Test.hasSelectItem }"
style="display:block;width:300px;height:360px;overflow:auto;" styleClass="panelGroup"
id="prefPanelGroup">
<h:selectManyCheckbox value="#{Test.selectedItems}" layout="pageDirection">
<f:selectItems value="#{Test.selectItems}" />
</h:selectManyCheckbox>
</h:panelGroup>
<hx:panelBox styleClass="information_box" id="noCommandWindow" layout="lineDirection"
rendered="#{!Test.hasSelectItem }">
<h:outputText styleClass="outputText" id="cmdInfo" value="#{nls.noCommands}" />
</hx:panelBox>
<hx:panelBox id="buttonBox1" styleClass="panelStartBox" layout="lineDirection">
<hx:commandExButton id="submitPref" styleClass="commandExButton" type="submit"
value="#{nls.submit}" action="#{Test.action}">
<hx:behavior event="onclick" behaviorAction="hide" targetAction="preferenceSet"
id="behaviorSubmitPref" />
</hx:commandExButton>
<hx:commandExButton id="CancelPref" styleClass="commandExButton" type="submit"
value="#{nls.cancel}" action="Test">
<hx:behavior event="onclick" behaviorAction="hide" targetAction="preferenceSet"
id="behaviorCancelPref" />
</hx:commandExButton>
</hx:panelBox>
</hx:panelDialog>
</h:form>
</td>
Code in Bean:
public class Test{
private List<String> selectedItems;
private List<SelectItem> selectItems;
public List<SelectItem> getSelectItems() {
// populate the selectItem here...
}
}

Store the List<SelectItem> selectItems in a separate session scoped bean (assuming that your current one is request scoped), fill it during its construction and add a method like reload() which you invoke only after processing the selected item in the action method. You can access the session scoped bean from inside the request scoped one by #ManagedProperty.

Related

h:selectBooleanCheckbox always pass false to validator

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 :)

Populate user form (edit row) with user-specific data in JSF Managed Bean

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.

Inserting multiple datas in 1 entity in a page

i have a CRUD generated create form:
<div class="create-form">
<h:form>
<h:inputText id="name" value="#{pointController.selected.name}" title="#{bundle.CreatePointTitle_name}" required="true" />
<h:inputText id="term" value="#{pointController.selected.term}" title="#{bundle.CreatePointTitle_term}" required="true" />
<p:commandButton styleClass="btn" action="#{pointController.create}" value="#{bundle.CreatePointSaveLink}" />
</h:form>
</div>
<button>add new form</button>
i have a button that if clicked it will create another form same as above using javascript. (2 inputText, name and term)
my goal is, with 2 or more forms, depending how many forms the user wants, with 1 commandButton that is clicked it will insert everything in the database.
example:
first form: name = first form test, term = first form testterm
2nd form: name = 2nd form test, term= 2nd form testterm
after clicking the command button
2 rows will be inserted in the same table in the database.
but i'm not sure what would be the structure for page for this.
You can't send data from many forms in a single request using JSF components, you should serialize all the data and send it manually. It would be better to have a List<Item> and every time you click in the button it will create a new item on the list and update an UIContainer that will display the items of the list.
This would be a start example of the above:
#ManagedBean
#ViewScoped
public class ItemBean {
private List<Item> lstItem;
public ItemBean() {
lstItem = new ArrayList<Item>();
addItem();
}
//getters and setter...
public void addItem() {
lstItem.add(new Item());
}
public void saveData() {
//you can inject the service as an EJB or however you think would be better...
ItemService itemService = new ItemService();
itemService.save(lstItem);
}
}
JSF code (<h:body> content only):
<h:form id="frmItems">
<h:panelGrid id="pnlItems">
<ui:repeat value="#{itemBean.lstItem}" var="item">
Enter item name
<h:inputText value="#{item.name}" />
<br />
Enter item description
<h:inputText value="#{item.description}" />
<br />
<br />
</ui:repeat>
</h:panelGrid>
<p:commandButton value="Add new item" action="#{itemBean.addItem}"
update="pnlItems" />
<p:commandButton value="Save data" action="#{itemBean.saveData}" />
</h:form>

JSF update inputText after selectOneMenu choice

I want to change the inputTexts' values when I choose another Skin from my selectOneMenu.
Everything is doing well, my Converter gives back the right Object from the menu, but the inputTexts are not updated.
<h:form>
<h:selectOneMenu id="dropdownSkin"
value="#{helloBean.currentSkin}" defaultLabel="Select a skin.."
valueChangeListener="#{helloBean.skinValueChanged}" immediate="true"
onchange="this.form.submit()" converter="SkinConverter" >
<f:selectItems value="#{helloBean.mySkinsSI}" var="c"
itemValue="#{c.value}" />
</h:selectOneMenu>
<br />
<h:inputText id="name" value="#{helloBean.currentSkin.title}"></h:inputText>
<br />
<h:inputText id="tcolor" value="#{helloBean.currentSkin.titleBar.textColor}"></h:inputText>
<br />
<h:inputText id="bcolor" value="#{helloBean.currentSkin.titleBar.backgroundColorStart}"></h:inputText>
</h:form>
Here is what my Bean looks like. I debugged it and the Object currentSkin is set correctly. Now i need to know how to update the textfields content.
#ManagedBean
#SessionScoped
public class HelloBean implements Serializable {
private static final long serialVersionUID = 1L;
private List<ExtendedSkin> mySkins;
private List<SelectItem> mySkinsSI;
private ExtendedSkin currentSkin;
public void skinValueChanged(ValueChangeEvent e) {
currentSkin = (ExtendedSkin) e.getNewValue();
FacesContext.getCurrentInstance().renderResponse();
}
public List<ExtendedSkin> getMySkins() {
mySkins = XMLParser.readExtendedSkins();
return mySkins;
}
public List<SelectItem> getMySkinsSI() {
mySkinsSI = new LinkedList<SelectItem>();
for (ExtendedSkin s : getMySkins()) {
mySkinsSI.add(new SelectItem(s, s.getTitle()));
}
return mySkinsSI;
}
public void setMySkinsSI(List<SelectItem> myItems) {
this.mySkinsSI = myItems;
}
public ExtendedSkin getCurrentSkin() {
if (currentSkin == null) {
currentSkin = getMySkins().get(0);
}
return currentSkin;
}
public void setCurrentSkin(ExtendedSkin currentSkin) {
this.currentSkin = currentSkin;
}
}
The problem here is that the converter is doing its work filling the helloBean.currentSkin object, but the values in the <h:inputText> that are bounded to this helloBean.currentSkin: title, textColor and backgroundColorStart will be send to the server and replace the actual values that were loaded by the converter. In other words:
The converter is executed and builds the helloBean.currentSkin based on the selected value.
The <h:inputText id="name"> empty value is sent to server and will be injected in helloBean.currentSkin.title. Same behavior for the other 2 <h:inputText>s.
The view will be loaded using the selected helloBean.currentSkin and it will load the helloBean.currentSkin.title with the empty value. Same behavior for the other 2 <h:inputText>s.
There are two possible solutions to this problem:
Move the <h:inputText>s outside the form, so the empty values won't be send to the server. When loading the view, it will maintain the values loaded in the converter.
<h:form>
<h:selectOneMenu id="dropdownSkin"
value="#{helloBean.currentSkin}" defaultLabel="Select a skin.."
valueChangeListener="#{helloBean.skinValueChanged}" immediate="true"
onchange="this.form.submit()" converter="SkinConverter" >
<f:selectItems value="#{helloBean.mySkinsSI}" var="c"
itemValue="#{c.value}" />
</h:selectOneMenu>
</h:form>
<br />
<h:inputText id="name" value="#{helloBean.currentSkin.title}"></h:inputText>
<!-- rest of Facelets code... -->
Since you're loading the helloBean.currentSkin while changing the selected value on your dropdownlist, you can add ajax behavior using <f:ajax> tag component inside the <h:selectOneMenu> and update the fields in a cleaner way. I would opt for this solution.
<h:form>
<!-- Note that there's no need of the onchange JavaScript function -->
<h:selectOneMenu id="dropdownSkin"
value="#{helloBean.currentSkin}" defaultLabel="Select a skin.."
valueChangeListener="#{helloBean.skinValueChanged}" immediate="true"
converter="SkinConverter" >
<f:selectItems value="#{helloBean.mySkinsSI}" var="c"
itemValue="#{c.value}" />
<f:ajax process="#this" render="name tcolor bcolor" />
</h:selectOneMenu>
<br />
<h:inputText id="name" value="#{helloBean.currentSkin.title}" />
<h:inputText id="tcolor" value="#{helloBean.currentSkin.titleBar.textColor}" />
<br />
<h:inputText id="bcolor"
value="#{helloBean.currentSkin.titleBar.backgroundColorStart}" />
</h:form>
You can learn more about <f:ajax> in online tutorial like this one.
Since you're going to use an ajax call in your page, you should change your managed bean scope from #SessionScoped to #ViewScoped. More info about this here: Communication in JSF 2

The last entry of the datagrid is lost while using partial processing with primefaces

i have a problem about partial processing. (I use primefaces 3.4.1.) I have a dataGrid listing services and each row of the dataGrid has a commandButton, "remove service", to remove the service.
I remove the specified service from my service list in my backing bean and update the datagrid while "remove service" button is clicked.
Also, i have two buttons in the form;
First button, "add service", works to add new service; I add a new object to my service list in my backing bean and update the datagrid while "add service" is clicked.
The second, "save", button works to save all services. When "save button" is clicked, service list is inserted to database.
Btw, i need form validation since there are mandatory fields in my service object. So, the form should be validated while "add service" and "save" are clicked. But, the form
shouldn't be validated while "remove service" button is clicked. If i use 'process="#form"' for "remove service" button, everything is ok. I can remove the specified service
from my service list in the backing bean and the datagrid is updated properly. But as u know, since all form is processed, all input components are validated. If i use 'process="#this"' or 'immediate="true"' for "remove service" button, i can not reach the last entry. I mean, i cannot reach the last service. I guess it hasn't been posted yet when i click the "remove service" button.
So, what should i do? Is there any suggestion about this situation? Thanks in advance...
My code is as below;
<h:form id="formServicesTab">
<h:panelGrid id="pnlSvcTab" columns="1" styleClass="valignTop" width="100%">
<p:dataGrid id="dgServices" var="service"
value="#{subMerchantOperations.subMerchantServices}"
columns="1" width="100%" styleClass="valignTop"
emptyMessage="#{messagebundle.submerc_grdlabel_no_service}" transient="true"
rowIndexVar="index" >
<p:toolbar>
<p:toolbarGroup align="left">
<p:commandButton id="btnRemoveSvc" onclick="loading.show();"
oncomplete="loading.hide();"
value="#{messagebundle.submerc_btn_delete_service}"
actionListener="#{subMerchantOperations.removeService}"
process="#form" update="#form">
<f:setPropertyActionListener target="#{subMerchantOperations.serviceRowIndex}" value="#{index}" />
</p:commandButton>
</p:toolbarGroup>
</p:toolbar>
<h:panelGrid columns="3" styleClass="valignTop" width="100%" bgcolor="F0F0F0">
<p:panel style="background:#F0F0F0;">
<h:panelGrid id="pnlDgSvc" columns="1" width="100%" style="height:100%">
<h:outputText value="#{messagebundle.submerc_label_svc_shortName}" />
<h:panelGrid columns="2">
<p:inputText id="txtSvcName" value="#{service.serviceName}"
required="true" transient="true"
requiredMessage="#{messagebundle.submerc_validation_msg_required}"
converter="UpperCaseConverter" />
<p:message for="txtSvcName" display="text" />
</h:panelGrid>
<h:outputText value="#{messagebundle.submerc_label_svc_website}" />
<p:inputText value="#{service.serviceUrl}" transient="true"/>
</h:panelGrid>
</p:panel>
<p:panel style="background:#F0F0F0;">
<h:panelGrid columns="1" width="100%">
..........
</h:panelGrid>
</p:panel>
<p:panel style="background:#F0F0F0;">
<h:panelGrid id="pgSvcFiles" columns="1" width="100%">
...........
</h:panelGrid>
</p:panel>
</h:panelGrid>
</p:dataGrid>
</h:panelGrid>
<p:toolbar style="background:white">
<p:toolbarGroup align="left">
<p:commandButton id="btnAddNewSvc"
value="#{messagebundle.submerc_btn_addSvc}"
actionListener="#{subMerchantOperations.addNewService}"
process="#form" update="#form" />
<p:commandButton id="btnSaveSubM"
value="#{messagebundle.submerc_btn_sendApproval}"
action="#{subMerchantOperations.saveServices}"
process="#form" update="#form" />
</p:toolbarGroup>
</p:toolbar>
</h:form>
#ManagedBean
#ViewScoped
public class SubMerchantOperations implements Serializable {
private static final long serialVersionUID = 8556103952857187080L;
private List<Service> subMerchantServices = new ArrayList<Service>();
private int serviceRowIndex;
// add new empty service to the service list
public void addNewService() {
try {
Service svc = new Service();
svc.setStartDate(new Date());
getSubMerchantServices().add(svc);
}
catch(Exception ex) {
if (logger.isEnabledFor(Level.ERROR)) {
...
}
}
}
// Remove the specified service using index parameter got from the datagrid
public void removeService() {
try {
getSubMerchantServices().remove(serviceRowIndex);
}
catch(Exception ex) {
...
}
}
// DB Operations
public String saveSubMerchant() {
...
}
public List<Service> getSubMerchantServices() {
return subMerchantServices;
}
public void setSubMerchantServices(List<Service> subMerchantServices) {
this.subMerchantServices = subMerchantServices;
}
public int getServiceRowIndex() {
return serviceRowIndex;
}
public void setServiceRowIndex(int serviceRowIndex) {
this.serviceRowIndex = serviceRowIndex;
}
}
I have no idea what that transient attribute is doing on your <p:dataGrid>. I have reviewed the latest published version of the Primefaces PDF documentation and this is not listed as a valid attribute.
If you are finding that Facelet-based component validation is causing your empty form to fire validation errors on submit of one of your buttons, you might consider creating a method in your backing bean which is called by your submit method, and validates the state of elements on the bean. This is a popular approach with Primefaces, because unlike Seam we are not provided with form-level validation.
However, do check your understanding of immediate=true.
Alternatively you might consider annotating your POJO's properties with JSR303 annotations.
Since you're using Collections, ensure that your Service POJO overrides equals and hashcode to rule out that something screwy isn't going on with your collection and causing your problem.

Resources