how to have more than one column of checkboxes in primefaces - primefaces

I need to do a user permissions grid hopefully using a primefaces datatable. For each row: Column one is a class name, Column two is a checkbox for permission for one of two subclasses. Column three is a checkbox for permission for the other subclass. The headers of columns two and three must have the subclass title plus a checkbox, the toggles all the other checkboxes in that subclass. I think I can use two or three datatables side by side inside a scrollpanel but I'm having issues lining up the column text to the left of the checkbox (it wants to go on top).
Another thing I tried was to just have a selectbooleancheckbox for each row for each subclass and then have a listener for the column header checkbox that iterates through each item in the list and set the value accordingly. The issue I have here is that when I update the datatable, then all the checkboxes get stuck in the 'checked' state.
This is what my grid:
----------------------------------------|
| Class | [] subclass 1 | [] subclass 2 |
| Cls A | [] | [] |
| Cls B | [] | [] |
| Cls n | [] | [] |
There are 'n' possible rows to this table.
Does anyone have examples of what I want to do that they can point me to?
Thanks,

To start of, make sure you have some kind of model where you can bind the checkboxes to. For example:
public class MyObject {
private String name;
private boolean bool1;
private boolean bool2;
// Add getters and setters
public MyObject(String name, boolean bool1, boolean bool2) {
this.name = name;
this.bool1 = bool1;
this.bool2 = bool2;
}
}
Then, in your bean add a list of booleans to store the state of the checkboxes in the header:
private List<MyObject> myObjects = new ArrayList<>();
private List<Boolean> headerChecks = new ArrayList<>();
// Add getter and setter
#PostConstruct
private void init() {
myObjects.add(new MyObject("Object 1", false, true));
myObjects.add(new MyObject("Object 2", false, false));
myObjects.add(new MyObject("Object 3", true, true));
headerChecks.add(false);
headerChecks.add(false);
}
Now, in the checkbox column header have a checkbox with a listener. In the listener set the state of all checkboxes of that column. Then update only the checkboxes in the column. To do so I've used a selector selecting elements with a specific class: #(.bool1).
<p:column>
<f:facet name="header">
<p:selectBooleanCheckbox id="bool1" value="#{myBean.headerChecks[0]}">
<p:ajax listener="#{myBean.headerClickListener}"
update="#(.bool1)"/>
</p:selectBooleanCheckbox>
<p:outputLabel for="bool1" value="Bool 1"/>
</f:facet>
<p:selectBooleanCheckbox value="#{item.bool1}" styleClass="bool1"/>
</p:column>
In listener the state of the corresponding row checkboxes is set:
public void headerClickListener(AjaxBehaviorEvent event) {
for (MyObject myObject : myObjects) {
if (event.getComponent().getId().equals("bool1")) {
myObject.setBool1(headerChecks.get(0));
}
if (event.getComponent().getId().equals("bool2")) {
myObject.setBool2(headerChecks.get(1));
}
}
}
The full table:
<p:dataTable id="dataTable" value="#{myBean.myObjects}" var="item">
<p:column headerText="Name">
<h:outputText value="#{item.name}"/>
</p:column>
<p:column>
<f:facet name="header">
<p:selectBooleanCheckbox id="bool1" value="#{myBean.headerChecks[0]}">
<p:ajax listener="#{myBean.headerClickListener}"
update="#(.bool1)"/>
</p:selectBooleanCheckbox>
<p:outputLabel for="bool1" value="Bool 1"/>
</f:facet>
<p:selectBooleanCheckbox value="#{item.bool1}" styleClass="bool1"/>
</p:column>
<p:column>
<f:facet name="header">
<p:selectBooleanCheckbox id="bool2" value="#{myBean.headerChecks[1]}">
<p:ajax listener="#{myBean.headerClickListener}"
update="#(.bool2)"/>
</p:selectBooleanCheckbox>
<p:outputLabel for="bool2" value="Bool 2"/>
</f:facet>
<p:selectBooleanCheckbox value="#{item.bool2}" styleClass="bool2"/>
</p:column>
</p:dataTable>
Please note that this is all quite WET. You might want to DRY stuff up a bit.
Result:

Related

Combine Drag&Drop and Reorder in a p:dataTable

I need to combine Drag and Drop and Reorder on a DataTable row. I know that there are ways to do this on different columns (like one column for the reorder, the other one for Drag and Drop), but I need to do it on one Element.
I tried different ways, but nothing worked. The Problem is, that once the reordering is triggered, I can't drop it in the area. It always returns to the end of the table.
Getting the mouse position wouldn't work, because i need to make it responsive and usable for mobile devices.
HTML:
<p:fieldset id="availableCarsField" legend="Available Cars">
<p:dataTable id="availableCars"
var="car"
widgetVar="widgetVarAvailableCars"
draggableRows="true"
value="#{dndCarsView.cars}">
<p:column id="dragColumn"style="width:20px;">
<h:outputText id="test" value="#{car.id}"/>
<p:draggable helper="clone" revert="true"/>
</p:column>
</p:dataTable>
</p:fieldset>
<!-- ........................... DROP ...........................-->
<p:fieldset id="selectedCars" legend="Selected Cars">
<p:outputPanel id="dropArea">
<h:outputText value="!!!Drop here!!!"
rendered="#{empty dndCarsView.droppedCars}"
style="font-size:24px;"/>
<p:dataTable id="selectedCarsTable"
var="car"
value="#{dndCarsView.droppedCars}"
rendered="#{not empty dndCarsView.droppedCars}">
<p:column headerText="Id">
<h:outputText value="#{car.id}"/>
</p:column>
</p:dataTable>
</p:outputPanel>
</p:fieldset>
<p:droppable for="selectedCars"
tolerance="touch"
activeStyleClass="ui-state-highlight"
onDrop="handleDrop"
datasource="availableCars">
<p:ajax listener="#{dndCarsView.onCarDrop}"
process="#form"
update="dropArea availableCars"/>
</p:droppable>
JS:
function handleDrop(event, ui) {
var droppedCar = ui.draggable;
droppedCar.fadeOut('fast');
}
Bean (in case it's required):
public class DNDCarsView implements Serializable {
private List<Car> cars;
private List<Car> droppedCars;
#PostConstruct
public void init() {
cars = createCars(9);
droppedCars = new ArrayList<>();
}
public List<Car> createCars(int size) {
List<Car> list = new ArrayList<>();
for (int i = 0; i < size; i++) {
list.add(new Car("" + i, "Brand" + i, i * 2000, "Color" + i));
}
return list;
}
public void onCarDrop(DragDropEvent ddEvent) {
Object car = ddEvent.getData();
droppedCars.add((Car) car);
cars.remove(car);
}
public void onReorder(ReorderEvent event) {
Car car = cars.get(event.getFromIndex());
cars.add(event.getToIndex(), car);
cars.remove(event.getFromIndex());
}
//Getter & Setter
}
Is there anyway to combine these two and get this running?
Thanks in advance
Edit:
I want to reorder the rows inside the DataTable and also be able to drop the dragged row into the fieldset.
Primefaces 6.2.12
JSF 2.2
Edit 2:
After month of trying I haven't found a good solution for my problem. Just thought, that I might share this here, if someone else deals with this problem.
I seems like there is no way to realize Drag&Drop in combination with columnreorder on one element (in my case p:column). The problem is, that always the reorderevent is triggered when dragged. When dropped into the droparea, the dragId of the dragged element is null (because we started with the reorder-event but ended with the event for drag and drop)
Due to the fact that I wasn't allowed to change anything which wasn't my class I didn't manage to fix this. I ended up to separate the actions onto two elementes. So I made a drag handle where the user can drag the element into the droparea and realized the reorder on the column.
If I was blind and someone knows an answer to this feel free to write. Maybe it might help someone. At least it would be interesting whether there is a way to do so

p:datascroller only lazyload one time

We have implement the datascroller from primefaces and extend it with lazy=true this works fine for the first lazy loading. But when I scroll down no event is fired from Frontend. The Backend works as expected.
I test it with changing the chunk size and get a better understanding what is happen in the backend code. We override the load function what primefaces is calling when you reach the end of page. I changed the code to not lazyloading by scrolling, therefor i implement a button to load the next chunk when you click the button. But Button disappear after clicking it once.
Xhtml:
<p:dataScroller value="#{stakeholderOverviewController.model}" var="stakeholder" chunkSize="50" lazy="true" rowIndexVar="test">
<f:facet name="header">
Scroll Down to Load More Cars
</f:facet>
<f:facet name="loader">
<p:commandButton type="button" value="More" icon="pi pi-chevron-circle-down"/>
</f:facet>
<h:panelGrid columns="2" style="width:100%" columnClasses="logo,detail">
<p:outputPanel>
<h:panelGrid columns="2" cellpadding="5">
<h:outputText value="Id:" />
<h:outputText value="#{stakeholder.lastname}" style="font-weight: bold"/>
<h:outputText value="Year:" />
<h:outputText value="#{stakeholder.firstname}" style="font-weight: bold"/>
</h:panelGrid>
</p:outputPanel>
</h:panelGrid>
<ui:include rendered="#{empty stakeholder}" src="/WEB-INF/compositions/stakeholderEmptyModel.xhtml" />
</p:dataScroller>
there is the backend code for Controller:
public StakeholderOverviewController() {
model = new LazyDataModel<StakeholderSearchWrapper>() {
#Override
public List<StakeholderSearchWrapper> load(int first, int pageSize, String sortField, SortOrder sortOrder,
Map filters) {
List<StakeholderSearchWrapper> execQuery = execQuery(first, pageSize);
return execQuery;
}
};
model.setRowCount(0);
}
....
protected synchronized List<StakeholderSearchWrapper> execQuery(int first, int pageSize) {
if (tmpfirst != first || tmppageSize != pageSize || reExecQuery) {
reExecQuery = false;
tmpfirst = first;
tmppageSize = pageSize;
tmpModel = new LinkedList<>();
// Query for stakeholder
queryresponse = stakeholderService.findByLastnameOrFirstmanOwnerOrShare(getSearchText(), getClientId(),
first, pageSize, selectedFacets, nameSort[getSort()]);
setFacets(queryresponse.getFacetFields());
Set<String> stakeholderIds = new HashSet<String>();
// convert for view
for (SolrDocument details : queryresponse.getResults()) {
StakeholderSearchWrapper stakeholderSearchWrapper = new StakeholderSearchWrapper(details);
tmpModel.add(stakeholderSearchWrapper);
stakeholderIds.add(stakeholderSearchWrapper.getId());
}
historyCount = stakeholderService.countHistoryEntryByStakeholders(stakeholderIds);
notesCount = stakeholderService.countNoteEntriesByStakeholders(stakeholderIds);
assignedProjects = projectService.findByStakeholderIds(stakeholderIds);
for(StakeholderSearchWrapper dao : tmpModel) {
dao.setHistoryCount(getHistoryCount(dao.getId()));
dao.setNoteCount(getNoteEntriesCount(dao.getId()));
dao.setProjects(getAssignedProjects(dao.getId()));
}
SolrDocumentList result = queryresponse.getResults();
int numFound = (int) result.getNumFound();
return tmpModel;
} else {
return tmpModel;
}
}
What i want is that the lazy loading dont fire only once. It should fire as often as needed. I dont know where i have to set some variable to do this. When im debuging the current code the load function is only requested at the first run of the page refresh and than one lazy loading is called but then nothing happens.
I think I realized the trick. Check the line:
model.setRowCount(0);
Instead, set the model row count properly using the max amount of data you want to display:
int totalNumberOfRegisters = this.count(/* relevant paramenters*/);
model.setRowCount(totalNumberOfRegisters);

Trigger notification bar from <p:ajax> event

I'm looking to trigger a notification bar on checkbox click using <p:ajax>. The notification bar would have the save option to save data in the database. The update atribute within <p:ajax> doesn't seem to work. It's been quite a research, but couldn't derive at a solution. Am I missing something here ? I'm using JSF 2.1+Primefaces 3.5. Any help would be much appreciated.
xhtml page
<p:column headerText="#{msgs.ref}" styleClass="menuHeader textAlignLeft">
<p:notificationBar widgetVar="customSaveBar" position="top" styleClass="saveBar warningBar textAlignCenter" style="height: 25px;padding-top: 0; padding-bottom: 0;" effect="none" rendered="true">
<h:outputText value="There are pending changes on the page." styleClass="warningText"/>
<h:outputText value=" "/>
<p:commandLink action="#{abcDashboardBean.abcDTOValues}"
onclick="skipPageRedirectWarning = true;showPleaseWait();"
styleClass="warningText" id="saveFromBar"
onsuccess="customSaveBar.hide()"
oncomplete="placeRemoveIcon();"
update="#form"
process="#form"
value="#{msgs.save}"/>
</p:notificationBar>
<p:selectBooleanCheckbox styleClass="margin_left_10" value="#{abcDto.refBl}"
rendered="#{!authorizationBean.userADMIN or !authorizationBean.userPM or !authorizationBean.userINDM}">
<p:ajax event="click" partialSubmit="true" update="customSaveBar"></p:ajax>
</p:selectBooleanCheckbox>
</p:column>
abcDashboardBean.java
public Map<Object, Boolean> getAbcDTOValues(){
Map<Object, Boolean> map = new LinkedHashMap<Object, Boolean>();
//fill the map with the items defaulted to unchecked
for (AbcDTO abcDTO: abcList){
map.put(abcDTO.getPpcCode(), Boolean.FALSE);
}
Abc abc1 = dataAccessEjbService.find(Abc.class, abc.getId());
saveAbcRefChanges(map, abc1);
return map;
}
public void saveAbcRefChanges(Map<Object, Boolean> map, Abc abc) {
for (Map.Entry<Object, Boolean> entry : map.entrySet()) {
if (entry.getValue().equals(true) && abc != null) {
abc.setReferenceBl(true);
} else {
abc.setReferenceBl(false);
}
}
dataAccessEjbService.update(abc);
}
AbcDTO.java
private boolean refBl;
// getters + setters

Cancel Edit Row Data table prime faces

I have data table is filled dynamically with records.I add ajax request on that data table on rowEdit event.
I want on the method that handle rowEdit event in the back bean to check on some criteria and if it true don't edit this row
i am using PF 3.1
thanks
<p:dataTable id="itemDT" var="item" value="#{itemView.items}" selectionMode="multiple"
selection="#{itemView.selectedItems}"
rowKey="#{item.Id}">
<p:ajax event="rowEdit"
listener="#{itemView.onRowEdit}" />
<p:column headerText="Input three">
<h:outputText value="#{item.inpt3}" />
    </p:column>
<p:column headerText="Input four">
<h:outputText value="#{item.inpt4}" />
    </p:column>
</p:dataTable>
and the back bean
#ManagedBean(name="itemView")
#ViewScoped
public class ItemView{
private ItemModel selectedItems[];
// getters and setters for selectedItems
private List<ItemModel> items;
// getters and setters for items
public void add(){
// add item to i.e database
}
public void insertRecord(){
// add itemModels to items list
}
public void onRowEdit(RowEditEvent event) {
//check if criteria then cancel editing
}
}

Primefaces Datatable dynamic calculation

In my view layer, I use a Primefaces Datatable with 9 columns, which the last one has float values (column name= 'Valor').
There is an integer column named 'prefDep' which has a filter for its values (foreignKey values, by the way):
<!-- column name omitted -->
<p:column sortBy="#{item.prefDep}" filterBy="#{item.prefDep}">
<h:outputText value="#{item.prefDep}"/>
</p:column>
The last row of the Datatable has a fixed GrandTotal, which is the overall sum of the mentioned 'Valor' column:
<p:columnGroup type="footer">
<p:row>
<p:column colspan="8" footerText="Grand Total:" />
<p:column footerText="#{upbController.totalLosses}" />
</p:row>
</p:columnGroup>
Method in the controller class to get the overall sum:
public int getTotalLosses() {
int total = 0;
for(Upb id : getItems()) {
total += id.getValor();
}
return total;
}
What I want: as I filter the Datatable, I want to show the corresponding GrandTotal for that filtered portion of values only, and not the 'fixed' overall sum.
How can I do it?
Thanks in advance.
--
After section:
In my AbstractController I have:
private List<T> filteredUpb;
//...
public List<T> getFilteredUpb() {
if (filteredUpb == null) {
filteredUpb = this.ejbFacade.findAll();
}
return filteredUpb;
}
In my UpbController (managedBean):
private List<Upb> filteredUpb = null;
//...
public int getPerdasTotal() {
int total = 0;
for (Upb id : getFilteredUpb()) {
total += id.getVlOco();
}
return total;
}
In jsf:
<p:column>
<f:facet name="footer">
<h:outputText value="#{upbController.perdasTotal}" />
</f:facet>
</p:column>
Just to not let this question unanswered, the solution (see below) for this question can be found in this other post of mine: Dynamic Calculation Using Filter in Datatable
I think that you can define AJAX calls on PF datatable filtering and/or paging.
<p:dataTable value="#{myBackingBean.values}" var="row" filteredValue="#{myBackingBean.filteredValues}" >
<p:ajax event="filter" listener="#{myBackingBean.updateSum}" update="componentToUpdate" />
//...
</p:dataTable>
In your updateSum() method, you can walk through the filteredValues collection to do your business.
You may have some difficulties to target the update component enclosed in the datatable but this can be resolved by adding something like styleClass="footerToUpdate" to your code and using it in the update with update="#(.footerToUpdate)"