Primefaces PickList transfer event - jsf

I have a picklist that contains a list of services
<h5> Pick A Service </h5>
<p:pickList id="pojoPickList"
responsive="true"
value="#{brancheController.serviceNames}"
var="service"
itemValue="#{service}"
itemLabel="#{service.serviceName}"
converter="#{serviceConverter}">
<f:facet name="sourceCaption">Available Services</f:facet>
<f:facet name="targetCaption">Assigned Services</f:facet>
<p:ajax event="transfer"
listener="#{brancheController.onTransfer}"/>
</p:pickList>
and in the backing Bean i have this method that get trigered whenever we have a transfer event
public void onTransfer(TransferEvent event) {
if (event.isAdd()) {
for (Object item : event.getItems()) {
notDuplicatedServices.remove((Service) item);
serviceNamesTarget.add((Service) item);
}
} else if (event.isRemove()) {
log.info(event.getItems().size());
for (Object object: event.getItems()) {
notDuplicatedServices.add((Service) item);
serviceNamesTarget.remove((Service) item);
}
}
When adding a service TransferEvent.isAdd() works fine but when removing a service event.getItems() is always empty
Can you please help me how to solve this and get removed services
Thank you in advance .

Related

A potential method invoking after a POST (basically Ajaxical) request finishes

While performing CRUD operations using JSF/PrimeFaces, a common method that resets managed bean fields/properties is generally needed which is to be invoked basically after one such operation is successfully completed so that the fields in the backing bean are reset to their initial (default) value.
Imaginary code :
#Named
#ViewScoped
public class Bean extends LazyDataModel<Entity> implements Serializable {
#Inject
private Service service; // EJB.
// Holds a list of selected rows in a <p:dataTable>.
private List<Entity> selectedValues; // Getter & setter.
private String someField; // Getter & setter.
// Other fields depending upon the business requirement.
public Bean() {}
#PostConstruct
private void init() {
// Do something.
}
#Override
public List<Entity> load(int first, int pageSize, List<SortMeta> multiSortMeta, Map<String, Object> filters) {
setRowCount(service.rowCount());
// Other complex logic as and when required.
return service.getList(first, pageSize, map, filters); // Returns a List<Entity>.
}
// Resets fields to their default value.
public void reset() {
someField = null;
selectedValues = null;
// Reset other fields to their default value.
}
// Add (insert submitted values to the database).
// This method is basically bound to an action(Listener) of <p:commandButton>.
public void submit() {
if (service.insert(someField)) {
// Add a FacesMessge to indicate a success.
reset(); // Calling reset.
} else {
// Add a FacesMessge to indicate a failure.
}
}
// Update the database using submitted values.
public void onRowEdit(RowEditEvent event) {
if (event.getObject() instanceof Entity) {
Entity entity = (Entity) event.getObject();
Entity newEntity = service.update(entity);
if (newEntity != null) {
// Update the model.
// Other things like adding a FacesMessage to indicate a success.
} else {
// Add a FacesMessage to warn against the null entity returned by the service layer.
}
} else {
// Add a FacesMessage to indicate a failure.
}
reset(); // Finally reset the fields to their initial/default value.
}
// Similarly, performing the delete operation also requires to call the reset() method.
}
The submit() method performing "insert" is basically associated with JSF/PrimeFaces command components like <p/h:commandButton> or <p/h:commandLink>. Such as.
<p:inputText value="#{bean.someField}"/>
<p:commandButton value="Submit"
actionListener="#{bean.submit}"
oncomplete="if(args && !args.validationFailed) {updateTable();}"/>
<!-- Updating a p:dataTable in question after the above p:commandButton completes. -->
<p:remoteCommand name="updateTable" update="dataTable" process="#this"/>
The following AJAX events associated with a <p:dataTable> also require to call the reset() method.
<p:ajax event="rowEdit"
onstart="..."
oncomplete="..."
update="..."
listener="#{bean.onRowEdit}"/>
<p:ajax event="rowEditCancel"
onstart="..."
oncomplete="..."
update="..."
listener="#{bean.reset}"/>
<p:ajax event="page"
onstart="..."
oncomplete="..."
update="..."
listener="#{bean.reset}"/>
<p:ajax event="sort"
onstart="..."
oncomplete="..."
update="..."
listener="#{bean.reset}"/>
<p:ajax event="filter"
onstart="..."
oncomplete="..."
update="..."
listener="#{bean.reset}"/>
As can be seen, the reset() method needs to be memorized carefully as it is invoked from several places. The way is somewhat difficult to maintain.
Does there exist a way to invoke such a common method automatically after each POST request performing one of the CRUD operations has finished its job successfully?
JSF doesn't have any tag for this.
Ideally, you'd like to have something like a <f:event type="postInvokeAction" listener="#{bean.reset}"> directly attached to the <p:dataTable>. But that event doesn't exist in JSF 2.2. OmniFaces has one, but it's only supported on UIViewRoot, UIForm, UIInput and UICommand.
The <f:phaseListener> comes close, but it gets attached to UIViewRoot directly, even though you place it inside <p:dataTable>. And, it requires a whole PhaseListener implementation.
The <f:view afterPhase> seems your best bet. You only need some additional checking on the phase ID and the source component.
<p:dataTable binding="#{table}" ...>
<f:view afterPhase="#{bean.reset(table)}" />
<p:ajax ... />
<p:ajax ... />
<p:ajax ... />
<p:ajax ... />
...
</p:dataTable>
public void reset(UIData table) {
FacesContext context = FacesContext.getCurrentInstance();
if (context.getCurrentPhaseId() != PhaseId.INVOKE_APPLICATION) {
return;
}
String source = context.getExternalContext().getRequestParameterMap().get("javax.faces.source");
if (!table.getClientId(context).equals(source)) {
return;
}
// Reset logic here.
// ...
}
(binding could if necessary be replaced by a hardcoded table client ID)
I understand that this is awkward. So, for the upcoming OmniFaces 2.2 I have altered the existing InvokeActionEventListener to support this use case too. It now supports being attached on any UIComponent.
<p:dataTable ...>
<f:event type="postInvokeAction" listener="#{bean.reset}" />
<p:ajax ... />
<p:ajax ... />
<p:ajax ... />
<p:ajax ... />
...
</p:dataTable>
public void reset() {
// ...
}

SelectOneMenu control not returning selected value

I am having a problem with the SelectOneMenu control. I want the the selected item to be be displayed via the valueChange Ajax event listen. But this is not happening.
However, when I change the value in the SelectOneMenu and then click on the Submit button, then selected value is getting displayed via the 'save' bean function
Cannot figure out why this is not working. Would appreciate any help on this.
Thanks.
The relevant xhtml code is as follows:
<h:form>
<h:dataTable value="#{dynamicList.myData}" var="item" >
<h:column>
<h:outputText value="#{item.oracleType}"></h:outputText>
</h:column>
<h:column>
<h:selectOneMenu value="#{item.coffeeFlavour}" rendered="#{item.showLov}" >
<f:selectItems value="#{item.coffeeList}"></f:selectItems>
<f:ajax event="valueChange" listener="#{dynamicList.listen}" ></f:ajax>
</h:selectOneMenu>
<h:inputText value="#{item.coffeeFlavour}" rendered="#{item.showText}">
</h:inputText>
</h:column>
</h:dataTable>
<p:commandButton value="Submit" action="#{dynamicList.save}" ></p:commandButton>
</h:form>
The relevant bean code is as follows:
#ManagedBean
#ViewScoped
public class DynamicList implements Serializable{
private List<OraclePrfl> oracleList=new ArrayList<OraclePrfl>();
private String coffee;
private Map<String,String> coffeeList=new LinkedHashMap<String,String>();
public List<OraclePrfl> getOracleList() {
return oracleList;
}
public List<OraclePrfl> getMyData()
{
oracleList.clear();
oracleList.add(new OraclePrfl("Oracle Lot Number",new HashMap<String,String>(){
{
put("Coffee2 - Cream Latte", "Cream Latte");
put("Coffee2 - Extreme Mocha", "Extreme Mocha");
put("Coffee2 - Buena Vista", "Buena Vista");
}
},true,false));
oracleList.add(new OraclePrfl("Oracle Product Number",new HashMap<String,String>(){
{
put("ABC", "abc");put("PQR", "pqr");put("XYZ", "xyz");
}
},true,false));
oracleList.add(new OraclePrfl("Oracle Specification",new HashMap<String,String>(){
{
put("MNP", "mnp");put("WXY", "wxy");put("XYZ", "xyz");
}
},true,false));
oracleList.add(new OraclePrfl("Address",false,true));
return oracleList;
}
public void setOracleList(List<OraclePrfl> oracleList) {
this.oracleList = oracleList;
}
public String getCoffee() {
return coffee;
}
public void setCoffee(String coffee) {
this.coffee = coffee;
}
public Map<String,String> getCoffeeList() {
coffeeList.clear();
coffeeList.put("Coffee2 - Cream Latte", "Cream Latte"); //label, value
coffeeList.put("Coffee2 - Extreme Mocha", "Extreme Mocha");
coffeeList.put("Coffee2 - Buena Vista", "Buena Vista");
return coffeeList;
}
public void setCoffeeList(Map<String,String> coffeeList) {
this.coffeeList = coffeeList;
}
public void save(){
for(OraclePrfl oracle:oracleList){
System.out.println("oracle type------"+oracle.getOracleType()+"------coffee----
"+oracle.getCoffeeFlavour());
}
}
public void listen(AjaxBehaviorEvent event){
System.out.println("calling listener "+event.getSource().toString());
for(OraclePrfl oracle:oracleList){
System.out.println("type....."+oracle.getOracleType()+"----value-----
"+oracle.getCoffeeFlavour());
}
}
}
Try removing the event:
<f:ajax listener="#{dynamicList.listen}" ></f:ajax>
It should default to event="change".

p:pickList doesn't update the source and target

I have been accessing the p:picklist for the first time and I am facing a issue where I am not able to get source and target values updated as in the p:picklist ui. I am using list of DualListModel<String>. Here is the code..
Please help me.
Thanks for the help!
code.xhtml
<p:dataTable value="#{updateSiteObj.dsList}" var="pickListObjDS" >
<p:column headerText="DS">
<p:pickList id="pojoPickListDSID" value="#{pickListObjDS}" var="ds" itemValue="#{ds}" itemLabel="#{ds}" showSourceFilter="true" showTargetFilter="true" filterMatchMode="contains" style="border-color: white!important" onTransfer="ajaxSubmit3()">
<f:facet name="sourceCaption">Available</f:facet>
<f:facet name="targetCaption">To be removed</f:facet>
</p:pickList>
<p:remoteCommand action="#{updateSiteObj.onDSTransfer}" name="ajaxSubmit3"/>
</p:column>
</p:dataTable>
UpdateSite.java
#ManagedBean(name = "updateSiteObj")
#SessionScoped
public class UpdateSite {
private List<DualListModel<String>> dsList = new ArrayList<DualListModel<String>>();
public List<DualListModel<String>> getDsList() {
return dsList;
}
public void setDsList(List<DualListModel<String>> dsList) {
this.dsList = dsList;
}
public String updateSiteDetails() {
ds.add(sg.getPrimaryDSID());
if (sg.getSecondaryDSID() != null) {
ds.add(sg.getSecondaryDSID());
}
System.out.print("DS:" + sg.getPrimaryDSID() + "=>" + sg.getSecondaryDSID());
DualListModel<String> tempDS = new DualListModel<String>();
tempDS.setSource(ds);
dsList.add(tempDS);
return "someSite?faces-redirect=true";
}
public void onDSTransfer() {
System.out.print("DSTransfer");
for (DualListModel<String> str1 : dsList) {
System.out.print("RemovedLBEntry:");
for (String dsName1 : str1.getTarget()) {
System.out.print("RemovedLB:" + dsName1);
}
}
}
}
When I try to call onDSTransfer after moving the values from source panel to target panel in picklist UI doesn't show any value from target.
Add update="#all" in p:remoteCommand.
You are doing a ajax call and not updating your UI.
<p:remoteCommand action="#{updateSiteObj.onDSTransfer}" name="ajaxSubmit3" update="#all"/>

t:dataScroller not working correctly on refresh

I'm using t:dataScroller to scroll some data from a t:dataTable and it is working fine except for one thing: every time an action that causes the screen to be refreshed is triggered the t:dataScroller's index is set to 1.
To be more clear: when i'm in the second page (index == 2) and a screen refreshing action triggers, after the refresh, the data of the dataTable is still from index 2 but the dataScroller shows that the page being displayed is the first one.
I'm using the dataScroller this way:
<t:dataScroller for="myDataTable" id="myDataScroller" paginator="true"
paginatorMaxPages="#{myBean.paginatorMxPgs}"
pageCountVar="pgCount" pageIndexVar="#{myBean.curPg}"
actionListener="#{myBean.pgListener}">
<f:facet name="prv">
<h:panelGroup rendered="#{myBean.curPg > 1}" />
</f:facet>
<f:facet name="nxt">
<h:panelGroup rendered="#{myBean.curPg != pgCount}"/>
</f:facet>
</t:dataScroller>
i'm using tomahawk20-1.1.11.jar and myfaces-api-2.0.4.jar
For setting scroller to firstpage set actionlistener on submit button.
<t:commandButton actionListener="#{IFussBean.resetDataScroller}"
action="#{IFussBean.searchLocation}"
image="images/submit-button.png">
</t:commandButton>
Binding:
if it is datatable
<t:dataTable id="data"
headerClass=""
footerClass=""
rowClasses="text_holder"
columnClasses="search_img,search_txt"
var="item"
value="#{IFussBean.searchVideoList}"
preserveDataModel="false"
rows= "6"
binding="#{IFussBean.iFussData}"
>
Declare HtmlDataTable in your Bean,define its setter getter as below:
private HtmlDataTable iFussData;
Getter and setter
public HtmlDataTable getiFussData() {
return iFussData;
}
public void setiFussData(HtmlDataTable iFussData) {
this.iFussData = iFussData;
}
Now define ActionListener Method in Bean:
public void resetDataScroller(ActionEvent e) {
if(iFussData!= null) {
iFussData.setFirst(0);
}
}
Your page will set to first page when you'll do new search.
/**********************************************************************************************************************************/
if you are using <rich:dataGrid> and your scroller is <t:dataScroller> then
<rich:dataGrid
id="data"
var="item"
columns="3"
elements="6"
width="600px"
value="#{IFussBean.searchVideoList}"
binding="#{IFussBean.iFussDataGrid}"
>
Declare HtmlDataGrid in Bean:
private HtmlDataGrid iFussDataGrid;
Its getter and setter
public HtmlDataGrid getiFussDataGrid() {
return iFussDataGrid;
}
public void setiFussDataGrid(HtmlDataGrid iFussDataGrid) {
this.iFussDataGrid = iFussDataGrid;
}
Now define its action listener in Bean which will invoke on pressing command button for search :
public void resetDataScroller(ActionEvent e) {
if(iFussDataGrid != null) {
iFussDataGrid.setFirst(0);
}
}
Invoke ActionListener on command button
<h:commandButton styleClass="submit-button" actionListener="#{IFussBean.resetDataScroller}" action="#{IFussBean.searchLocation}" image="images/submit-button.png"/>
It also give desire result.

JSF PrimeFaces FileDownload problem

I'm using PrimeFaces for a new project and it's quite an impressive set of components.
Anyway, I have problem with "real world" use of filedownload component.
In my page I have a datalist that shows the attachments related to a particular document, and I want provide a link to directly download that file inside the datalist item.
Here's my xhtml code:
<p:dataList id="ListaAllegati" value="#{documentBean.documento.allegati}" type="definition" var="attach" style="border: none" ">
<f:facet name="description">
<h:outputText value="#{attach.name}" />
<p:commandLink ajax="false" title="Download" action="#{documentBean.selectAttach}>
<h:graphicImage style="margin-left: 10px; border: none" value="./images/article.png" height="24" width="24" ></h:graphicImage>
<p:fileDownload value="#{documentBean.downloadFile}"/>
<f:setPropertyActionListener target="#{documentBean.selectedAttach}" value="#{attach}" />
</p:commandLink>
</f:facet>
</p:dataList>
and the relative java bean (request scoped):
private StreamedContent downloadFile;
public StreamedContent getDownloadFile() {
log.info("getter dell'allegato invocato");
InputStream stream = null;
byte[] rawFile = null;
if (selectedAttach == null) {
log.warn("Nessun allegato passato");
return null;
} else {
try {
log.info("Recupero del file " + selectedAttach.getGuid());
rawFile = attachManager.retrieveFile(selectedAttach.getGuid());
} catch (Exception e) {
String msg = "Errore durante il recupero del file";
log.error(msg, e);
FacesMessage fmsg = new FacesMessage(msg, "");
FacesContext.getCurrentInstance().addMessage(null, fmsg);
}
stream = new ByteArrayInputStream(rawFile);
DefaultStreamedContent file = new DefaultStreamedContent(stream,
selectedAttach.getMimeType(), selectedAttach.getName());
return file;
}
}
public void selectAttach() {
log.info("commandLink action invocata");
}
private Allegato selectedAttach;
public Allegato getSelectedAttach() {
return selectedAttach;
}
public void setSelectedAttach(Allegato selectedAttach) {
log.info("Allegato selezionato");
if (selectedAttach==null) log.warn("L'allegato passato รจ nullo");
this.selectedAttach = selectedAttach;
}
So, couple of question:
Am I doing the right thing trying to pass the selected attachment that way? Otherwise, how can I pass a parameter to tell the bean wich attachment has been clicked?
Why the first time I click the command link, nothing happen? It make a roundtrip with server, but nothing happens. Second time, it gives me an exception.
Why documentBean.selectAttach is never called and the documentBean.selectedAttach property is never set (neither the second time)?
Thanks to anyone for any hint
How to get the row object from the datatable is answered in this question:
How can I pass selected row to commandLink inside dataTable?
This answers basically all the three questions.
As to the exception in the second click, that's likely because you didn't return from the catch block when an exception is been thrown in your getDownloadFile() method. You're continuing the remnant of the code flow while the rawFile is still null. Fix it accordingly as well. Add a return null to the end of catch or something. Better yet, you should be posting the entire stacktrace in the question as you don't seem to be able to understand it. It basically already contains the answer :)
Primefaces has its own dedicated servlet for file download and upload components that handle all of this asynchronously.
Try doing something like what I have in my code
<p:commandLink ajax="false" actionListener="#{managedBean.downloadAction(object)}">
<span class="ui-icon icoFolderGo" style="padding-right: 1.5em;" />
<p:fileDownload value="#{managedBean.downloadContentProperty}" />
</p:commandLink>
And in the managed bean,
public void downloadAction(Object object) {
try {
InputStream stream = // get input stream from argument
this.setDownloadContentProperty(new DefaultStreamedContent(stream, "application/pdf", "filename.pdf");
} catch (Exception e) {
log.error(e);
}
}
public void setDownloadContentProperty(StreamedContent downloadContentProperty) {
this.downloadContentProperty = downloadContentProperty;
}
public StreamedContent getDownloadContentProperty() {
return downloadContentProperty;
}

Resources