I have created selectALL checkbox functionality in jsf + icefaces. and i have implemented functionality like when i check selectAll checkbox it is selecting all the checkboxes across all the pages. but when i do pagination and if i do checked/unchecked select all checkbox then its works for only that page not acorss all the pages. i mean the state of row checkboxes is not consistent. i tried phaseListener for solving this but no luck.. can anyone suggest me the solution..
my code : jsf
<ace:column id="checkBox">
<f:facet name="header">
<h:outputLabel>
<ice:selectBooleanCheckbox id="selectAllID"
value="#{shipBean.checkAll}"
valueChangeListener="#{shipBean.getCheck}"
partialSubmit="true" />
</h:outputLabel>
</f:facet>
<ice:selectBooleanCheckbox id="selectOne"
value="#{freight.checkBox}">
java:
if (shipTrackingData != null) {
if (shipTrackingData.getCheckAll()) {
for (ShipTrackBean check : shipTrackingData
.getShipTrackList()) {
check.setCheckBox(true);
}
} else {
for (ShipTrackBean check : shipTrackingData
.getShipTrackList()) {
check.setCheckBox(false);
}
}
}
Thanks...
I have tested this code for a JSF application, I have three pages:
index_1.xhtml
index_2.xhtml
index_3.xhtml
#ManagedBean
#SessionScoped
public class pross {
private boolean challval=false;
private boolean chval1=false;
private boolean chval2=false;
private boolean chval3=false;
.. getters and setters....
}
In each page I created two checkboxes one of them is to be selected across all pages if selected in any of them, but that checkbox is related to the same value (challval) for all pages.
there is also another checkbox for the page itself, one for each (chval1,chval2,chval3).
To test this I wrote this xhtml code for every page but you need to change the values according to each page, here is the code for index_1.xhtml, you need to change "go to" links to be able to access other pages:
<h:body>
<h:form>
Hello, Test checkboxes:
<br />
Select this page: <h:selectBooleanCheckbox value="#{pross.chval1}" >
<f:ajax render="outthis outall"/>
</h:selectBooleanCheckbox>
This page select: <h:outputText id="outthis" value="#{pross.chval1}"/>
<br/>
Select all pages: <h:selectBooleanCheckbox value="#{pross.challval}">
<f:ajax render="outthis outall"/>
</h:selectBooleanCheckbox>
all pages select: <h:outputText id="outall" value="#{pross.challval}"/>
<br/>
<h:link outcome="index_2" value="Go to page 2" />
<br/>
<h:link outcome="index_3" value="Go to page 3" />
</h:form>
</h:body>
I see no problem here, and when I check "select all" in one page, it is still checked in the others, I think the idea is to connect the "select all" checkbox with same bean value for all pages.
Hope this is useful, thanks.
Related
In normal circumstances like this:
<h:form>
<h:selectOneRadio value="#{bean.gender}">
<f:selectItem itemValue="Male" itemLabel="Male" />
<f:selectItem itemValue="Female" itemLabel="Female" />
<f:selectItem itemValue="Other" itemLabel="Other" />
</h:selectOneRadio>
<h:commandButton value="Submit" action="#{bean.action}" />
</h:form>
Selecting one radio button disselects the other & the radio button will be remain selected on the postback. (when the same view is rendered)
However, when we're dealing with an iterating component like <h:dataTable>, the selection is lost.
Consider the snippet:
<h:form id="hashMapFormId">
<b>HASH MAP:</b>
<h:dataTable value="#{playersBean.dataHashMap.entrySet()}" var="t" border="1">
<h:column>
<f:facet name="header">Select</f:facet>
<h:selectOneRadio id="radiosId" onclick="deselectRadios(this.id);"
value="#{playersBean.select}">
<f:selectItem itemValue="null"/>
</h:selectOneRadio>
</h:column>
</h:dataTable>
<h:commandButton value="Show Hash Map Selection"
action="#{playersBean.showSelectedPlayer()}" />
</h:form>
With disselecting the other radio buttons when one radio button is selected being implemented by simple JavaScript-
function deselectRadios(id) {
var f = document.getElementById("hashMapFormId");
for (var i = 0; i < f.length; i++)
{
var e = f.elements[i];
var eid = e.id;
if (eid.indexOf("radiosId") !== -1) {
if (eid.indexOf(id) === -1) {
e.checked = false;
} else {
e.checked = true;
}
}
}
}
Fire the GET request:
Select a radio button:
Now press the submit button, response:
You see that the radio button gets dis selected on postback. How to solve this shortcoming?
I know it very well that this is due to this component attribute itemValue being null:
<f:selectItem itemValue="null"/>
This trick is a leftover from JSF 1.x / 2.0/2.1 when it wasn't possible to use a <h:selectOneRadio> for single row selection in a <h:dataTable>. This trick originated in my 10 year old blog article Using Datatables - Select row by radio button.
The root problem is, HTML radio buttons are grouped based on their name attribute, so the webbrowser knows which others to unselect when one is selected. But JSF generates by design a different one for each <h:dataTable> item, with the row index inlined and therefore they can't be grouped and hence the JavaScript based workaround.
Since JSF 2.2, with the new passthrough elements and attributes feature, it's however possible to force the name attribute to the value of your choice and capture the selected item via a helper <h:inputHidden>. This is fleshed out in another blog article of me, from previous year: Custom layout with h:selectOneRadio in JSF 2.2. The article uses <ui:repeat> as an example, this can be rewritten to <h:dataTable> as below.
<h:form>
<h:dataTable value="#{bean.items}" var="item">
<h:column>
<input type="radio" jsf:id="item" a:name="#{hiddenItem.clientId}"
value="#{item.id}" a:checked="#{item.id eq bean.selectedItemId ? 'checked' : null}" />
</h:column>
<h:column>#{item.id}</h:column>
<h:column>#{item.name}</h:column>
</h:dataTable>
<h:inputHidden id="selectedItem" binding="#{hiddenItem}" value="#{bean.selectedItemId}"
rendered="#{facesContext.currentPhaseId.ordinal ne 6}" />
<h:commandButton id="submit" value="Submit" action="#{bean.submit}" />
</h:form>
#Named
#ViewScoped
public class Bean implements Serializable {
private List<Item> items;
private Long selectedItemId;
// ...
public void submit() {
System.out.println("Selected item ID: " + selectedItemId);
}
// ...
}
And yes, the selected radio button remains selected on postback this way. You can also pass whole entities, this only requires a converter on the <h:inputHidden>.
I have a JSF 2 application that has two pages, one to list students and one to show details of a given student. The listing page has a link to the details page in each row of the students table, that opens a new tab in browser to show those details, when clicked.
Now the requirements changed to no more show details in a new tab, but in a modal dialog in the listing page.
My idea is to simply embed the details page content in the modal dialog so the listing page will not get too big and hard to maintain. Here start my doubts. After some research I changed the link in each row of the listing to the following button:
<p:commandButton value="Details" type="button"
onclick="PF('dialog-details').show()">
</p:commandButton>
The dialog is declared as follows:
<p:dialog widgetVar="dialog-details" header="Details" modal="true" width="95%">
<ui:include src="student_details.xhtml">
<ui:param name="id" value="#{student.id}"/>
</ui:include>
</p:dialog>
Finally, the details page was changed to be something like this:
<ui:composition
xmlns="http://www.w3.org/1999/xhtml" xmlns:f="http://java.sun.com/jsf/core"
xmlns:p="http://primefaces.org/ui" xmlns:h="http://java.sun.com/jsf/html"
xmlns:ui="http://java.sun.com/jsf/facelets">
<f:metadata>
<f:viewParam name="id" value="#{studentBean.id}" />
</f:metadata>
<h1 class="title ui-widget-header ui-corner-all">Details of #{studentBean.bean.name} / #{studentBean.bean.number}</h1>
</ui:composition>
When I click the button, the dialog really shows and the content is the details page. I see the following content in the dialog:
Details of /
No errors at all, but the data that should be shown, isn't. A breakpoint was set in StudentBean.setId() (this method loads a property named bean with the Student instance corresponding to the passed id) but it is never hit.
After some time thinking about it, I came to understand why it does not work. The parameter passed to the details page is student.id, but student is the name used as the var in the <p:datatable/> that show all the students, so student is not valid in <p:dialog/> which is outside the <p:datatable/>.
So, what I need is a way to show the dialog using the id of the corresponding student in a given row. Ideally, I would like an ajax call here, so the details would loaded only when neded.
Any ideas?
The button should be an ajax button which sets the currently iterated entity in the bean, and then updates the dialog's content, and finally shows it. The dialog should just reference that entity in the bean and update the list and table on save. It's very important that dialog is placed outside the main form and that it has its own form.
Here's a kickoff example:
<h:form id="master">
<p:dataTable value="#{bean.entities}" var="entity">
<p:column>#{entity.property1}</p:column>
<p:column>#{entity.property2}</p:column>
<p:column>#{entity.property3}</p:column>
...
<p:column>
<p:commandButton value="View" action="#{bean.setEntity(entity)}"
update=":detail" oncomplete="PF('detail').show()" />
</p:column>
</p:dataTable>
</h:form>
<p:dialog id="detail" widgetVar="detail">
<h:form>
<p:inputText value="#{bean.entity.property1}" />
<p:inputText value="#{bean.entity.property2}" />
<p:inputText value="#{bean.entity.property3}" />
...
<p:button value="Close" onclick="PF('detail').hide(); return false" />
<p:commandButton value="Save" action="#{bean.save}"
update=":master" oncomplete="if(!args.validationFailed) PF('detail').hide()" />
</h:form>
</p:dialog>
With this inside a #ViewScoped bean:
private List<Entity> entities; // +getter
private Entity entity; // +getter+setter
#EJB
private EntityService entityService;
#PostConstruct
public void load() {
entities = entityService.list();
entity = null;
}
public void save() {
entityService.save(entity);
load();
}
See also:
Creating master-detail pages for entities, how to link them and which bean scope to choose
Creating master-detail table and dialog, how to reuse same dialog for create and edit
Keep p:dialog open when a validation error occurs after submit
Difference between rendered and visible attributes of <p:dialog>
How to display dialog only on complete of a successful form submit
I have a JSF 2 application that has two pages, one to list students and one to show details of a given student. The listing page has a link to the details page in each row of the students table, that opens a new tab in browser to show those details, when clicked.
Now the requirements changed to no more show details in a new tab, but in a modal dialog in the listing page.
My idea is to simply embed the details page content in the modal dialog so the listing page will not get too big and hard to maintain. Here start my doubts. After some research I changed the link in each row of the listing to the following button:
<p:commandButton value="Details" type="button"
onclick="PF('dialog-details').show()">
</p:commandButton>
The dialog is declared as follows:
<p:dialog widgetVar="dialog-details" header="Details" modal="true" width="95%">
<ui:include src="student_details.xhtml">
<ui:param name="id" value="#{student.id}"/>
</ui:include>
</p:dialog>
Finally, the details page was changed to be something like this:
<ui:composition
xmlns="http://www.w3.org/1999/xhtml" xmlns:f="http://java.sun.com/jsf/core"
xmlns:p="http://primefaces.org/ui" xmlns:h="http://java.sun.com/jsf/html"
xmlns:ui="http://java.sun.com/jsf/facelets">
<f:metadata>
<f:viewParam name="id" value="#{studentBean.id}" />
</f:metadata>
<h1 class="title ui-widget-header ui-corner-all">Details of #{studentBean.bean.name} / #{studentBean.bean.number}</h1>
</ui:composition>
When I click the button, the dialog really shows and the content is the details page. I see the following content in the dialog:
Details of /
No errors at all, but the data that should be shown, isn't. A breakpoint was set in StudentBean.setId() (this method loads a property named bean with the Student instance corresponding to the passed id) but it is never hit.
After some time thinking about it, I came to understand why it does not work. The parameter passed to the details page is student.id, but student is the name used as the var in the <p:datatable/> that show all the students, so student is not valid in <p:dialog/> which is outside the <p:datatable/>.
So, what I need is a way to show the dialog using the id of the corresponding student in a given row. Ideally, I would like an ajax call here, so the details would loaded only when neded.
Any ideas?
The button should be an ajax button which sets the currently iterated entity in the bean, and then updates the dialog's content, and finally shows it. The dialog should just reference that entity in the bean and update the list and table on save. It's very important that dialog is placed outside the main form and that it has its own form.
Here's a kickoff example:
<h:form id="master">
<p:dataTable value="#{bean.entities}" var="entity">
<p:column>#{entity.property1}</p:column>
<p:column>#{entity.property2}</p:column>
<p:column>#{entity.property3}</p:column>
...
<p:column>
<p:commandButton value="View" action="#{bean.setEntity(entity)}"
update=":detail" oncomplete="PF('detail').show()" />
</p:column>
</p:dataTable>
</h:form>
<p:dialog id="detail" widgetVar="detail">
<h:form>
<p:inputText value="#{bean.entity.property1}" />
<p:inputText value="#{bean.entity.property2}" />
<p:inputText value="#{bean.entity.property3}" />
...
<p:button value="Close" onclick="PF('detail').hide(); return false" />
<p:commandButton value="Save" action="#{bean.save}"
update=":master" oncomplete="if(!args.validationFailed) PF('detail').hide()" />
</h:form>
</p:dialog>
With this inside a #ViewScoped bean:
private List<Entity> entities; // +getter
private Entity entity; // +getter+setter
#EJB
private EntityService entityService;
#PostConstruct
public void load() {
entities = entityService.list();
entity = null;
}
public void save() {
entityService.save(entity);
load();
}
See also:
Creating master-detail pages for entities, how to link them and which bean scope to choose
Creating master-detail table and dialog, how to reuse same dialog for create and edit
Keep p:dialog open when a validation error occurs after submit
Difference between rendered and visible attributes of <p:dialog>
How to display dialog only on complete of a successful form submit
I have a JSF MyFaces dataTable that contains a list of elements and a column with a delete button. All I want to do is to popup a dialog when clicking on the delete button that would allow the user to confirm or cancel the operation.
I already have the dialog (reduced for simplicity and using <a> because of the lack of HTML5 support):
<div id="myModal">
<h:form>
<a data-dismiss="modal">Close</a>
<h:commandLink action="#{somethingMagicInHere?}">Confirm</h:commandLink>
</h:form>
</div>
In the dataTable I have something like this (also simplified):
<h:dataTable id="myDataTable" value="#{bean.elementList}" var="element">
<h:column>
<f:facet name="header">Actions</f:facet>
<a class="call-modal">Delete</a>
</h:column>
</h:dataTable>
Finally my ManagedBean looks like this:
#ManagedBean(name = "bean")
#RequestScoped
public class ElementClassBean {
...
public String actionToPerform(ElementClass e) {
MyBusinessLogicModel.getInstance().deleteElement(e);
}
}
So, in short, jQuery executes when loading the page and takes all elements with class call-modal and sets an onclick to them so that they display the component with id myModal, which is of course the modal window. I inherited this working this way and prefer not change it but any solution or ideas will help.
I can use a commandLink directly in the dataTable that would access actionToPerform(element) from the view but that, of course, won't fire the modal. So the main issue I see, given this structure, is how can I send the element being iterated in the dataTable to the modal once the Delete button is clicked? (I don't mind if the solution uses Ajax).
Any input will be helpful. Thanks.
Ok, this is the ugly but working solution that doesn't require me to refactor all the views and managed beans. In short: I added a hidden input field that would store the id of the element to delete in the modal form. In the datatable all I do is setting the value of the hidden input field once the button is clicked and fire the modal. The modal is then filled with the just updated value.
My simplified modal:
<div id="myModal">
<h:form id="myForm">
<h:inputHidden value="#{bean.elementIdInModal}" id="elementIdInModal"/>
<a data-dismiss="modal">Close</a>
<h:commandLink action="#{bean[actionToPerform]}">Confirm</h:commandLink>
</h:form>
</div>
My simplified dataTable:
<h:dataTable id="myDataTable" value="#{bean.elementList}" var="element">
<h:column>
<f:facet name="header">Actions</f:facet>
<h:link styleClass="call-modal"
onclick="$('#myForm\\:elementIdInModal').val(#{element.id})">
Delete
</h:link>
</h:column>
</h:dataTable>
My simplified ManagedBean:
#ManagedBean(name = "bean")
#RequestScoped
public class ElementClassBean {
private long elementIdInModal; // Ommiting getters and setters
public void actionToPerform() {
MyBusinessLogicModel.getInstance().deleteElement(elementIdInModal);
}
}
I've been using JSF for a while but there's something that has always confused me. Hopefully someone can help.
Simple example, there's a page that shows a table of "Person"s and when you click on the "Person" name, it takes you to a page to view the details of the "Person".
Typically, I implement a personSearch.jsf page like this:
<h:dataTable value="#{personHandler.persons}" var="person">
<h:column>
<h:commandLink action="#{personHandler.show( person.id )}" >
<h:outputText value="#{person.name}" />
</h:commandLink>
</h:column>
</h:dataTable>
And I implement a personView.jsf page like this:
<h:panelGrid columns="2">
<h:outputText value="Person ID:" />
<h:outputText value="#{personHandler.selectedPerson.id}" />
<h:outputText value="Person Name:" />
<h:outputText value="#{personHandler.selectedPerson.name}" />
</h:panelGrid>
PersonHandler.show(Integer personId) sets personHandler.selectedPerson and then redirects to the personView page.
This all works fine when PersonHandler is a session bean. But I prefer it to be a request scoped bean because the user may have several windows open and I don't want there to be only one selected person per session.
So my question is, what's the "correct" way to do this JSF? I was once able to get what I wanted using a4j:keepAlive on the personHandler, but that always felt like a kludge. Again, this is something I've never understood about JSF.
Any help is greatly appreciated!
rob
If the view is supposed to be bookmarkable, pass the person ID as a GET request parameter instead of a POST request "parameter".
<h:outputLink value="viewperson.xhtml">
<f:param name="id" value="#{person.id}" />
</h:outputLink>
This way you can use two #RequestScoped beans, one for the list and one for the view. You can preload the selected person as follows:
#ManagedProperty(value="#{param.id}")
private Long id;
#PostConstruct
public void init() {
selectedPerson = personDAO.find(id);
}
If it is not supposed to be bookmarkable, then just create a single view which renders the view state conditionally.
<ui:fragment rendered="#{!personHandler.viewMode}">
<h:form>
<h:dataTable value="#{personHandler.persons}" var="person">
<h:column>
<h:commandLink value="#{person.name}" action="#{personHandler.show(person)}" />
</h:column>
</h:dataTable>
</h:form>
</ui:fragment>
<ui:fragment rendered="#{personHandler.viewMode}">
<h:form>
...
<h:commandLink value="Go back" action="#{personHandler.back}" />
</h:form>
</ui:fragment>
(You can if necessary split out the content of the both framgents to another Facelet files which you include by <ui:include>)
This way you can use a single #ViewScoped bean with action methods returning void or null.
public void show(Person selectedPerson) {
this.selectedPerson = selectedPerson;
}
public void back() {
selectedPerson = null;
}
public boolean isViewMode() {
return selectedPerson != null;
}
You can even wrap the whole view in some
<h:panelGroup id="container">
and nest the following in both command links to let Ajax magic do the work
<f:ajax execute="#form" render=":container" />