I have a simply facelet which display a list of products in tabular format. In the last column of each row, there is a checkbox used to mark the product for deletion. Until now i have to put a selectBooleanCheckBox on each row and have a "mark for deletion" property in the Product entity but i think it's ugly because i have some presentation stuff in my model bean.
Is there anyway to have a h:selectManyCheckBox which has its f:selectItem distribute on each row of the dataTable ?
Thank you
The t:selectManyCheckbox layout="spread" is an excellent suggestion.
As an alternative, you can also just bind the h:selectBooleanCheckbox component to a Map<Long, Boolean> property where Long represents the entity ID (or whatever identifier which you can use to identify the row) and Boolean represents the checked state.
E.g.
public class Bean {
private List<Entity> entities;
private Map<Long, Boolean> checked = new HashMap<Long, Boolean>();
public void submit() {
for (Entity entity : entities) {
if (checked.get(entity.getId())) {
// Entity is checked. Do your thing here.
}
}
}
// ...
}
with
<h:dataTable value="#{bean.entities}" var="entity">
<h:column>
<h:selectBooleanCheckbox value="#{bean.checked[entity.id]}" />
</h:column>
...
</h:dataTable>
<h:commandButton value="submit" action="#{bean.submit}" />
The Map<Long, Boolean> will be automagically filled with the ID of all entities as map keys and the checkbox value is set as map value associated with the entity ID as key.
See also:
Using datatables - Select multiple rows
You can, using MyFaces Tomahawk's <t:selectManyCheckbox> with layout="spread"
In my application, i have used below set of code to get multiple checkbox list to be displayed vertically with scrollbar:
<style type="text/css">
#productCategoryId label {
float: inherit;
font-size: 10px!important;
font-weight: normal;
}
#productCategoryId table.formTable th, table.formTable td {
padding: 0px 0px 0 0;
}
</style>
<div style="width:200px;height: 280px;overflow-y:scroll;overflow-x:hidden;border:1px solid #999;" max-height=280px>
<h:selectManyCheckbox id="productCategoryId" layout="pageDirection" style="width:200px" styleClass="changeId">
<f:selectItem itemValue="-1000" itemLabel="ALL" />
<f:selectItems value="#{lookup.list['RSM_LOOKUP']['PRODUCT_CATEGORY']}"/>
</h:selectManyCheckbox >
</div>
The best way to use selectManyCheckbox and dataTable is...
=== Page.xhtml ===
<ice:selectManyCheckbox id="idSelectManyCheckbox" layout="spread"
value="#{MyBean.selectedsValuesCheckbox}" >
<f:selectItems value="#{MyBean.selectItemsCheck}"/>
</ice:selectManyCheckbox>
<ice:dataTable varStatus="rowVar"
value="#{MyBean.listOfMyObjects}" var="anyNameVar">
<ice:column>
<ice:checkbox for="idSelectManyCheckbox" index="#{rowVar.index}" />
</ice:column>
<ice:column>
<ice:outputText value="#{anyNameVar.property1}" />
</ice:column>
<!-- ... more columns .. -->
</ice:dataTable>
=== MyBean.java ===
private List<MyObject> listOfMyObjects = new ArrayList<MyObject>(3);
private List<String> selectedsValuesCheckbox = new ArrayList<String>(2);
private SelectItem[] selectItemsCheck = new SelectItem[3];
private handleSelectItemsCheck(){
int idx = 0;
selectedsValuesCheckbox.add("1");
selectedsValuesCheckbox.add("3");
for (MyObject myObject : listOfMyObjects) {
selectItemsCheck[idx++] =
new SelectItem(myObject.property1, myObject.property2); // value and label
}
}
// Gets and sets
================================================================
*you must use layout="spread" in that situation.
*in the table the checkboxs 1 and 3 will be selected. because "selectedsValuesCheckbox"
Related
edit: Based on Jasper's comment, the selection feature requires p:dataTable to be in a form, so my question is moot.
I have a DataTable outside of a form. When I submit the form (non-ajax), the field referenced by the selection attribute is set to null in my view. This happens for PrimeFaces 10.0.1 and higher. In 10.0.0 and 8.x, the field is not touched.
The field in the example is DtView.selectedEntry.
xhtml:
<!DOCTYPE html>
<html xmlns="http://www.w3.org/1999/xhtml"
xmlns:p="http://primefaces.org/ui"
xmlns:h="http://xmlns.jcp.org/jsf/html">
<h:head>
<title>PrimeFaces Test</title>
</h:head>
<h:body>
<p:dataTable id="data-table" var="entry"
value="#{dtView.entries}"
rowKey="#{entry.id}"
selection="#{dtView.selectedEntry}"
selectionMode="single">
<p:column headerText="Entry">
<h:outputText value="#{entry}" />
</p:column>
</p:dataTable>
<h:form id="frmTest">
<div>
<p:outputLabel for="#next" value="Selected: "/>
<h:outputText id="selected-entry" value="#{dtView.selectedEntry}" />
</div>
<div>
<p:commandButton value="save input"
ajax="false"
imediate="true"
update="#form :data-table"
action="#{dtView.submit()}" />
</div>
</h:form>
</h:body>
</html>
View:
#Data
#Named
#ViewScoped
public class DtView implements Serializable {
private List<Product> entries;
private Product selectedEntry;
#PostConstruct
void setup() {
entries = List.of(
new Product(1, "entry 1"),
new Product(2, "entry 2"),
new Product(3, "entry 3")
);
selectedEntry = entries.get(0);
}
public String submit() {
System.out.println("Selected entry: " + selectedEntry);
return null;
}
}
Console (PrimeFaces 11.0.0 and then 10.0.0):
Selected entry: null
Selected entry: Product(id=1, name=entry 1)
To avoid the 'null' I can put p:dataTable inside a form, so it won't get processed during the apply request value phase or use ajax on the command button. I am not sure why the dataTable is outside a form in my real application to begin with.
I expected a value outside of a form not to be set in the view, but dataTable does not seem to follow this. Is the new PF behaviour more logical and my understanding is wrong?
The reason for this change seems to be located in SelectionFeature.
PF 8: just calls table.setSelection(null);:
https://github.com/primefaces/primefaces/blob/cd4fbdf1d9d4ae054da19b9a84001d0c34d142eb/src/main/java/org/primefaces/component/datatable/feature/SelectionFeature.java#L78
PF 10.0.0: decodeSingleSelection() does not call setSelection() because !rowKeys.isEmpty() evaluates to false (empty check disappears in 10.0.1):
https://github.com/primefaces/primefaces/blob/10.0.0/src/main/java/org/primefaces/component/datatable/feature/SelectionFeature.java#L84
11.0.0: decodeSingleSelection() eventually calls setSelection() to set the value in the view to null:
https://github.com/primefaces/primefaces/blob/11.0.0/primefaces/src/main/java/org/primefaces/component/datatable/feature/SelectionFeature.java#L87
In my jsf page, in a dialog, I have a list of EntityB which depends on selected EntityA in a datatable.
When I first load the page it's giving me nullPpointer exception because nothing is selected in the first place. Can anyone tell me how to prevent this?
EDIT: I added an actionlistener to the link who open the dialog
and getting this error:
Cannot convert DemandesDocsAdministratif type DemandesDocsAdministratif to class javax.faces.event.ActionEvent
JSF:
<p:commandLink value="#{demande.idDemandeDocAdministratif}"
oncomplete="PF('dlg2').show()" process="#this"
update=":form:pg" actionListener="#{gestionDemandesMB.fillEntityB}">
<f:setPropertyActionListener
target="#{gestionDemandesMB.SelectedEntityA}" value="#{demande}"
/>
</p:commandLink>
<form>
<datatable>
</datatable>
<p:dialog>
<p:selectOneMenu id="Signataires"
value="#{gestionDemandesMB.entityB}">
<f:selectItems value="#{gestionDemandesMB.listEntityB}"
var="sign" itemLabel="#{sign.libRole}"
itemValue="#{sign.idPoste}" />
</p:selectOneMenu>
</p:dialog>
</form>
Bean:
public List<EntityA> getListEntityB() {
if ( selectedentityA != null ){
return entityBService.ListByentityA(selectedEntityA)
; } else {
return Collections.emptyList() ; }
Bean listener that I'm working with now:
public void fillSignataires(ActionEvent event)
{
listB = entityBService.ListByentityA(selectedEntityA)
signaRender = true ;
}
this is the getter of entity B list, I'm looking for a way to either get an empty list or call only when I open dialog.
You could use rendered="#{not empty bean.list}" to prevent the rendering of the selectOnMenu until you have the object filled.
You can also add a f:selectItem with a "Select" label and empty itemValue such as itemValue = " ". By the way, never have a null list, list shouldn't be null but it can be empty. It's the best practice. So you can initialize your listEntityB as an empty list at post construct of your bean.
<p:selectOneMenu id="Signataires"
value="#{gestionDemandesMB.entityB}">
<f:selectItem itemLabel="Select" itemValue="" />
var="sign" itemLabel="#{sign.libRole}"
<f:selectItems value="#{gestionDemandesMB.listEntityB}"
var="sign" itemLabel="#{sign.libRole}"
itemValue="#{sign.idPoste}" />
</p:selectOneMenu>
I have a need to continuously update a page with new data produced by managedbeans. Managedbean creates a new List of values for every few minutes and UI must create a OutputText for each of the value in the newly created List by managedbean. Catch is, the UI should retain the outputTexts and add new one's for every request, it should not refresh/remove old outputTexts.
My code is like below - updates the same outputText fields for each ajax call, which I need to change like mentioned above.
<c:forEach var="data" items="#{myBean.dataList}">
<p:fieldset legend="#{data}" toggleable="true" toggleSpeed="500">
<h:panelGrid columns="2" cellpadding="5" border="0">
<p:scrollPanel style="height:300px">
<p:poll interval="2" listener="#{myBean.getDataList}" update="field1 field2"/>
<h:outputText value="#{data.field1}" id="field1"/>
<h:outputText value="#{data.field2}" id="field2"/>
</p:scrollPanel>
</h:panelGrid>
</p:fieldset>
</c:forEach>
so for each ajax call, there may be few data items produced by managedbeans and for each of those item there should be a new outputText field.
You can use datalist for <h:outputText value="#{data.field1}" id="field1"/>
Make a list and use them as outputtext, yes you need some css formatting because datalist used default css. sample code
<p:poll interval="3" listener="#{yourbean.yourmethod}" update="<updatecomponet>" />
<p:dataList value="#{yourbean.tempList}" var="s" id="updatecomponet">
<p:outputLabel value="#{s}"></p:outputLabel>
</p:dataList>
Note: You need to add value in list when poll call listener. it is working in my project, let me know for anything else. Hope this will help.
Maybe not the perfect solution, but you can use a DataTable with lazy loading, the poll component can update the datatable page and you don't need to update a huge amount of components.
Edit:
xhtml
<p:dataTable var="v"
value="#{myBean.getLazyList}"
scrollRows="1"
liveScroll="true"
rows="20"
scrollHeight="300"
lazy="true"
scrollable="true"
id="tsUpdates">
<p:column>
<h:outputText value="#{v.fields1}" />
</p:column>
</p:dataTable>
Bean
public class Bean {
private LazyDataModel<MyClass> lazyList;
#Named("myBean")
#ViewScoped
#PostConstruct
public void init() {
lazyList = new LazyMyClassModel(); //where myList is your data source
}
//getters and setters
}
LazyModel
public class LazyMyClassModel extends LazyDataModel<MyClass>{
private Integer findAllCount;
public LazyMyClassModel(){
}
#Override
public List<MyClass> load(int first, int pageSize, String sortField, SortOrder sortOrder,Map<String, String> filters){
List<MyClass> myList = //your live source of data
List<MyClass> data = new ArrayList<MyClass>();
data = getSubList(MyList, first, pageSize)
if (findAllCount == null) {
findAllCount = myList.size
this.setRowCount(findAllCount);
}
return data
}
public List<MyClass> getSubList(List<MyClass> list, int fromIndex, int toIndex) {
int size = list.size();
if (fromIndex >= size || toIndex <= 0 || fromIndex >= toIndex) {
return Collections.emptyList();
}
fromIndex = Math.max(0, fromIndex);
toIndex = Math.min(size, toIndex);
return list.subList(fromIndex, toIndex);
}
}
I am trying to make a form with options to add rows. However, after I type in some input and click the add button again, the input I enter disappears. I'm not sure what is wrong with my code. In addition, when I click the add button, the page refreshes. Is there way to stop this page refresh?
Person.java
public class Person{
private List<String> guys = new ArrayList<String>();
public List<String> getGuys() {
return guys;
}
public void setGuys(List<String> guys) {
this.guys = guys;
public void addNewItem(){
guys.add("");
}
}
form.xhtml
<h:form>
<h:panelGrid columns="2">
<h:outputText value="Guys: " />
<h:dataTable value="#{person.guys}" var="men">
<h:column>
<p:inputText value="#{men}" />
</h:column>
</h:dataTable>
<h:commandButton name="add" value="Add" action="#{person.addNewItem}" />
</h:panelGrid>
<br />
<h:commandButton name="submit" type="submit" value="Submit"></h:commandButton>
</h:form>
Provided that the bean is placed in the right scope for the functional requirement, the view scope, the only major mistake left is that you're expecting that the String class has some magic setter method.
It hasn't. The String class is immutable. The following will never work on a String:
<p:inputText value="#{men}" />
You have 2 options:
Create a real model class. You can find complete examples in the following answers:
How to dynamically add JSF components
Recommended JSF 2.0 CRUD frameworks
Set the value by row index instead:
<h:dataTable binding="#{table}" value="#{person.guys}">
<h:column>
<p:inputText value="#{person.guys[table.rowIndex]}" />
</h:column>
</h:dataTable>
(note: no additional bean property necessary for the table! the code is as-is)
This does basically a person.getGuys().add(table.getRowIndex(), submittedValue). I.e. the setter is invoked on the List itself, which works perfectly fine. See also the following related answers concerning ui:repeat:
Using <ui:repeat><h:inputText> on a List<String> doesn't update model values
How map multiple inputText to an array property?
You never update your list, you are just adding empty items. You should do something like this:
Person.java (viewscoped)
public class Person implements Serializable {
private List<String> guys = new ArrayList<String>();
private HtmlDataTable dtGuys;
public void addNewItem() {
guys.add("");
}
public void addToList(ValueChangeEvent e) {
guys.set(dtGuys.getRowIndex(), e.getNewValue().toString());
}
public String save() {
System.out.println("saving...");
for (String item : guys) {
System.out.println("item= " + item);
}
return null;
}
//gettes and setters
}
form.xhtml
<h:form id="frmPrincipal">
<h:panelGrid columns="2">
<h:outputText value="Guys: " />
<h:dataTable value="#{person.guys}" var="men" binding="#{person.dtGuys}" >
<h:column>
<p:inputText value="#{men}" valueChangeListener="#{person.addToList}" />
</h:column>
</h:dataTable>
<h:commandButton name="add" value="Add" action="#{person.addNewItem}" />
</h:panelGrid>
<br />
<h:commandButton id="submit" name="submit" value="Submit" action="#{person.save}"/>
</h:form>
Using jsf 2.0.10 and primefaces 3.5
Its because you don't have an scope for that bean, so its request scoped, so when you call the action the bean is created again, you can fix this using a sessionScope or conversationScope
I have a scenario to achieve but I don't know how to do it(I'am using primefaces)
The scenario is:
I have a selectOneMenu that contain options that the user can choose one of them,
when the user choose an option ,a "form" or a "Sub-page" should appear below the selectOneMenu , the user should fill it.
The "Sub-page" change according to the choosen option
eg :option1 ---> Sub-Page1
option2 --->Sub-Page2 etc..
JSF
<h:selectOneMenu style="width:200px" immediate="true" value="#{ToolsKPI.myChoice}" onchange="submit()" valueChangeListener="#{BeanTest.selectChangeHandler}" required="true" >
<f:selectItems value="#{ToolsKPI.getMyListKPI()}" />
</h:selectOneMenu>
<p:panel rendered="#{BeanTest.showPanelBool}" >
<h1>KPI1</h1>
<br></br>
<h:inputText value="test1" />
</p:panel>
<p:panel rendered="#{BeanTest.showPanelBool1}" >
<br></br>
<h1>KPI2</h1>
<h:inputText value="test2" />
<h:inputText value="test3" />
</p:panel>
My Bean
public class BeanTest implements java.io.Serializable {
private String myChoice;
private boolean showPanelBool;
private boolean showPanelBool1;
public BeanTest() {
}
//getters ande setters
public void selectChangeHandler(ValueChangeEvent event){
myChoice = (String) event.getNewValue(); // Must however be the exact page URL. E.g. "contact.jsf".
FacesContext.getCurrentInstance().getExternalContext();
if(myChoice.equals("Number Of Closed issues") ){
this.showPanelBool = true;
} else{
this.showPanelBool = false;
this.showPanelBool1 = true;
}
FacesContext.getCurrentInstance().renderResponse();
}
}
You should really post some semblance of the code: a picture something. What you're probably looking for is a "p:outputPanel" component or something similar.
http://www.primefaces.org/showcase/ui/outputPanel.jsf
You can do something with a ValueChangeListener akin to
public void onSelectItem(ValueChangeEvent evt)
{
if("someValue".equals(evt.getNewValue())
showPageOne = true;//boolean
else
showPageTwo = true;//boolean
}
//JSF
<h:form id="myForm">
<h:selectOneMenu valueChangeListener="#{myBean.onSelectItem}" update="myForm">
<f:selectItems value="items">
</h:selectOneMenu>
<p:outputPanel rendered="#{myBean.showPageOne}">
hi I'm page one
</p:outputPanel>
<p:outputPanel rendered="#{myBean.showPageTwo}">
hi I'm page two
</p:outputPanel>
</h:form>
Sorry for the pseudo code, the examples on Primefaces will really help you here. OutputPanel has saved my bacon often. You'll need to specify an update target, but the example is really clear and easy to run. Play with it.
(Also Primefaces is fantastic you'll likely be very happy with their component suite)