p:filedownload from p:datatable with ViewScoped managed bean wont work. It calls the methods prepareFile and getFile twice. In first call of the methods I mentioned it sets the first file from the table, and in the second call of the methods it sets the right file, but it always downloads only the first one and the second one is never downloaded.
Why does it call twice? Why does it set the first file from the table? Any ideas?
Here's my code:
<p:dataTable id="offer_attachment_datatable"
widgetVar="offer_attachment_datatable"
var="attachment"
value="#{offerBean.offerAttachments}">
<p:column>
<f:facet name="header"/>
<p:commandLink ajax="false" actionListener="#{offerBean.prepareFile(attachment)}" title="#{attachment.name}">
<p:graphicImage value="/resources/themes/navigator_b2e/images/drive-download.png" />
<p:fileDownload value="#{offerBean.file}"/>
</p:commandLink>
</p:column>
</p:dataTable>
and in managed bean (simplified):
private StreamedContent file;
private InputStream stream;
public void prepareFile(OfferAttachment attachment){
System.out.println("Attachment: "+attachment.getName());
stream = new ByteArrayInputStream(attachment.getAttachment());
file = new DefaultStreamedContent(stream, "text/plain", attachment.getName());
stream = null;
}
public StreamedContent getFile() {
System.out.println("File: "+file.getName());
return file;
}
public void setFile(StreamedContent file) {
this.file = file;
}
So, I made a workaround with a simple p:confirmDialog where I extracted the problematic ajax=false command link, so I select the attachment by clicking it in p:datatable and execute the download from the p:confirmdialog.
I had the same problem in 2.2.1. I found the solution by replacing p:commandLink to p:commandButton with the same attributes. Seems that it is a bug related with behavior of the commandLink component
Ok, guys, so I made a workaround with a simple p:confirmDialog where I extracted the problematic ajax=false command link, so I select the attachment by clicking it in p:datatable and execute the download from the p:confirmdialog.
The solution that worked for me was to replace "p:datatable" with "ui:repeat(facelets) and table", like this:
<table role="grid">
<thead>
<tr role="row">
<th>File Name</th>
<th>Action</th>
</tr>
</thead>
<tbody>
<ui:repeat value="#{downloadFileBean.files}" var="f">
<tr role="row">
<td><h:outputText value="#{f.name}" /></td>
<td>
<p:commandLink id="download" ajax="false">
<h:outputText value="Download" />
<p:fileDownload value="#{downloadFileBean.file}" />
<f:param name="fileName" value="#{f.name}" />
</p:commandLink>
</td>
</tr>
</ui:repeat>
</tbody>
Related
How to make some button which can skip web required validation(but still I want to process all data, so immediate and so on cannot be true).
Important is that it must be universal. At the moment I am using in every required field condition with some request param. Code example below
<p:inputText value="#{cc.attrs.data.exampleData1}"
required="#{param['onlySave'] == null}"/>
<p:inputText value="#{cc.attrs.data.exampleData2}"
required="#{param['onlySave'] == null}"/>
<p:inputText value="#{cc.attrs.data.exampleData3}"
required="#{param['onlySave'] == null}"/>
<p:commandButton value="Zapisz zmiany"
action="#{cc.attrs.controller.save()}"
update="#form">
<f:param name="onlySave" value="true"/>
</p:commandButton>
This solution is fine cause I can in every page just add this param to button and it skips validation, but when my save button not making any redirect, in case of failed some java validation in save method, I am just adding some message without redirect and then I lost all required styles from inputs.
Is there any possibility to set onlySave param to null in save method when validation failed or maybe some better solutions?
Edit: Balus answer great, but with bean validation like:
#Pattern(regexp = "^([^0-9]*)$", message = "only non numbers")
String field;
It processes to bean all data beyond that field. The best would be ignore only required field property, not validation etc.
Edit2:
<tr>
<td class="label">
<p:outputLabel id="label" for="#{cc.attrs.componentId}" value="#{cc.attrs.label}"/>
</td>
<td class="value">
<cc:insertChildren/> --here component with componentId
</td>
</tr>
<tr class="errorMessage">
<td class="label"/>
<td class="value">
<p:message id="error" for="#{cc.attrs.componentId}" />
</td>
</tr>
Please see below modified code for required fields. You can use #{empty param.onlySave} for the fields which you want to skip the validation and as per your requirements.
<p:inputText value="#{cc.attrs.data.exampleData1}"
required="#{not empty param.onlySave}"/>
<p:inputText value="#{cc.attrs.data.exampleData2}"
required="#{not empty param.onlySave}"/>
<p:inputText value="#{cc.attrs.data.exampleData3}"
required="#{not empty param.onlySave}"/>
<p:commandButton value="Zapisz zmiany"
action="#{cc.attrs.controller.save()}"
update="#form">
<f:param name="onlySave" value="true"/>
</p:commandButton>
So far the best solution i figured out is:
//p:label and p:message with property for=someId for each input above
<p:inputText id="someId" value="#{cc.attrs.data.exampleData1}"
required="#{param['onlySave'] == null}"/>
<p:inputText value="#{cc.attrs.data.exampleData2}"
required="#{param['onlySave'] == null}"/>
<p:inputText value="#{cc.attrs.data.exampleData3}"
required="#{param['onlySave'] == null}"/>
<p:commandButton value="save only"
action="#{cc.attrs.controller.save()}"
update="#(.ui-message,.ui-outputlabel)">
<f:param name="onlySave" value="true"/>
</p:commandButton>
<p:commandButton value="accept button"
action="#{cc.attrs.controller.accept()}"
update="#form">
</p:commandButton>
The save button just updates only all errors and labels, so I am able to see converters errors etc, but I dont lost required styles on inputs. In this example I just lost red color of input borders.
If u re using * in labels for required fields, dont update .ui-outputlabel
I figured out a solution :
JSF page
<h:form id="form" prependId="false">
<c:if test="#{param['onlySave'] eq true}">
<c:set value="#{false}" target="#{myBean}" property="required"/>
</c:if>
<p:inputText value="#{myBean.required}"/>
<p:growl id="msgs" showDetail="true" />
<p:inputText id="data1" value="#{myBean.data1}"
required="#{myBean.required}" />
<p:inputText id="data2" value="#{myBean.data2}"
required="#{myBean.required}"/>
<p:inputText id="data3" value="#{myBean.data3}"
required="#{myBean.required}"/>
<p:commandButton value="Zapisz zmiany"
action="#{myBean.save}" />
</h:form>
Bean
#ManagedBean
#ViewScoped
public class MyBean implements Serializable{
private String data1, data2, data3;
private boolean required;
#PostConstruct
public void init(){
required = true;
}
public void save() {
System.out.println(data1+", "+data2+", "+data3);
required = false;
//FacesContext.getCurrentInstance().addMessage(null, new FacesMessage(FacesMessage.SEVERITY_INFO,"Info","Saved"));
// FacesContext.getCurrentInstance().getExternalContext().getRequestMap().put("onlySave", "false");// FacesContext.getCurrentInstance().getExternalContext().getRequestMap().get("onlySave"));
}
// ... Getters & Setters
}
I use inputText, commandButton and uploadFile components. In commandButton, i have used ajax=false and made required=true in both the fields. When click on save with empty values, error message is not getting displayed in the dialog and dialog is getting closed. But in console, warning messages are displaying like "Messages are rendered but not displayed".
Below is my code:
<p:dialog widgetVar="addDialogWidgetVar" id="addDialogWidgetVarId" dynamic="true" >
<table style="width: 100%;">
<tr>
<td>
<p:messages for="errorMsgId" id="errorMsgId" autoUpdate="true" showDetail="false" showSummary="true" closable="true"/>
</td>
</tr>
</table>
<h:form id="formId" enctype="multipart/form-data">
<table>
<tr>
<td>
<label style="margin-top: 5%"><h:outputText value="Name:"/><h:outputText value="*" style="color:red"/></label>
</td>
<td width="10%"/>
<td>
<p:inputText value="#{manageBean.attachment.fileName}" id="fileNameId" maxlength="60" style="width:70"
required="#{not empty param[save.clientId]}" requiredMessage="Please enter Attachment name"></p:inputText>
</td>
</tr>
<tr height="10"></tr>
<tr>
<td>
<label style="margin-top: 5%"><h:outputText value="Upload Attachment:"/><h:outputText value="*" style="color:red"/></label>
</td>
<td width="10%"/>
<td>
<p:fileUpload label="Select a file" mode="simple" value="#{manageBean.attachment.file}"
allowTypes="/(\.|\/)(pdf|doc|docx|xls|xlsx|gif|jpg|jpeg|png|PNG|GIF|JPG|JPEG)$/"
invalidFileMessage="Allow only (pdf|doc|docx|xls|xlsx|gif|jpg|jpeg|png|PNG|GIF|JPG|JPEG) file."
multiple="false" required="#{not empty param[save.clientId]}" requiredMessage="Please select a file" >
</p:fileUpload>
</td>
</tr>
</table>
<br />
<table style="margin-left: 30%;">
<tr align="center">
<td>
<p:commandButton value="Close" actionListener="#{manageBean.cancelAttachment}" oncomplete="addDialogWidgetVar.hide()" />
</td>
<td>
<p:commandButton id="submitbtnid" value="Save" ajax="false" binding="#{save}"
actionListener="#{manageBean.saveAttachment}" update=":errorMsgId"/>
</td>
</tr>
</table>
</h:form>
</p:dialog>
When the values are empty, error message should be displayed in dialog itself.
That is expected behavior when you use ajax=false because on submit whole page is refreshed and that is why the dialog gets closed.
Also, in your p:messages component, you shouldn't have for attribute that points out to errorMsgId. In for you should put id of the input field you wan't to show messages from. For example, if you put formId:fileNameId, it will show error when you don't enter file name. But if you don't have for, it will show all the messages.
And you do not need update=":errorMsgId" since you have already put autoUpdate="true".
Now, to accomplish what you need, and show messages with ajax=false without closing dialog, there is this workaround:
JSF (in place where your save button is defined): *Save button redefined later
<p:commandButton id="submitbtnid" **style="display:none"** ajax="false" binding="#{save}" actionListener="#{manageBean.saveAttachment}" />
<p:commandButton value="Save" oncomplete="checkIfValid(xhr, status, args)" />
And JavaScript function:
function checkIfValid(xhr, status, args)
{
if (!args.validationFailed)
{
$("#formId\\:submitbtnid").click();
}
}
So, here is visible button which uses ajax and calls JS method to check if validation failed. And only if all validation conditions passed, it will click invisible button which actually submits the form.
UPDATE
For fileUpload input there should be an extra check. In this way, you can remove allowTypes an required attributes from fileUpload component, and add it an id - all validation will be in JavaScript function.
This is your fileUpload component:
<p:fileUpload label="Select a file" mode="simple" value="#{manageBean.attachment.file}" multiple="false"></p:fileUpload>
And you should also add hiddenInput in your form (and messageHidden field in your bean):
<h:inputHidden id="errorMsg" value="#{manageBean.messageHidden}"/>
Now, this is JavaScript function that does file input validation:
function checkFileInput() {
if ($("#formId\\:fileInput")[0].files.length == 0) {
$("#formId\\:errorMsg").val("Please select a file");
return;
}
var validExtensions = ['pdf','doc','docx','xls','xlsx','gif','png','jpg','jpeg'];
var maxFileSize = 5000;
var ext = $('#formId\\:fileInput').val().split('.').pop().toLowerCase();
if($.inArray(ext, validExtensions) == -1) {
$("#formId\\:errorMsg").val("Allow only (pdf|doc|docx|xls|xlsx|gif|jpg|jpeg|png|PNG|GIF|JPG|JPEG) file.");
return;
}
if ($("#formId\\:fileInput")[0].files[0].size > maxFileSize) {
$("#formId\\:errorMsg").val("File is to big");
return;
}
$("#formId\\:errorMsg").val("");
}
It first checks if the file is selected, then its extension and then allowed file maximum size. And if something of that isn't valid, it sets new value to hidden input field.
Now, in your bean, you should check if file validation went OK:
public void validateFile() {
if(!messageHidden.trim().equals("")) {
FacesContext.getCurrentInstance().validationFailed();
FacesMessage message = new FacesMessage(FacesMessage.SEVERITY_ERROR, messageHidden, messageHidden);
FacesContext.getCurrentInstance().addMessage(null, message);
}
}
If it didn't, validation failed will be set to the context and message from inputHidden will be added.
And, at last, you should change Save button to first check file input with JS, then validate it with bean method, and at the and check if validation failed:
<p:commandButton value="Save" onclick="checkFileInput()" actionListener="#{testBean.validateFile}"
oncomplete="checkIfValid(xhr, status, args)" />
I have a problem about reference in a form.
In the same form, I have a
- table generated with tags
- a panel, allowing user to edit cell content (with multiple inputs and informations)
I use a <p:commandButton> with a <f:setPropertyActionListener> to store the cell value and refresh the detail's panel. This part as no problem.
When the user's edit ends, he save its changes by clicking on "save" button in the detail panel. I'd like to refresh only the previously selected cell and not the whole table.
So I had a to save the Component.clientId and put a "renderer=xxx" on the button to be sure the id is not null.
But it always throws javax.faces.FacesException...
<table class="measureTable" id="measureTable">
<!-- header -->
<tbody ... >
<tr class="ui-column-title">
<th ...> ...</th>
<ui:repeat var="columnHeader" value="#{managedBean.columnModels}" id="columnHeaders" >
<th ><p:outputLabel value="#{columnHeader.name}" /></th>
</ui:repeat>
</tr>
<!-- datas -->
<ui:repeat var="vLine" value="#{managedBean.roundvLines}" id="lines" >
<tr>
<td >
<p:panel styleClass="cellPanel">
<p:outputLabel value="#{vLine.id}" styleClass="ui-column-header" />
</p:panel>
</td>
<ui:repeat var="vCell" value="#{vLine.cells}" id="cells">
<td>
<p:commandButton styleClass="cellPanel" value="#{vCell.value}" update=":formControl:detailPanel" >
<f:setPropertyActionListener value="#{vCell}" target="#{managedBean.currentCell}" />
<f:setPropertyActionListener value="#{component.clientId}" target="#{managedBean.currentComponentId}" />
</p:commandButton>
</td>
</ui:repeat>
</tr>
</ui:repeat>
</tbody>
</table>
<p:panel id="detailPanel">
<p:panel rendered="#{!empty managedBean.currentCell}" styleClass="panelWithoutBorder">
<ui:param name="definition" value="#{managedBean.currentCell.measureDefinition}"/>
<ui:param name="measure" value="#{managedBean.currentCell}"/>
<p:panel id="detailValue" header="Valeur">
<!-- NUM -->
<p:keyboard value="#{measure.value}" keypadOnly="true"
rendered="#{definition.codeTypeSais == 1}" />
<!-- STR -->
<p:keyboard value="#{measure.value}"
rendered="#{definition.codeTypeSais == 2}"/>
...
</p:panel>
...
<p:panel>
<p:commandButton value="refresh" update=":formControl:specimen:0"
rendered="#{!empty managedBean.currentComponentId}"></p:commandButton>
</p:panel>
</p:panel>
</p:panel>
GRAVE: javax.faces.FacesException: Cannot find component with expression ":formControl:lines:0:cells:0:j_idt20" referenced from "j_idt36".
at org.primefaces.expression.SearchExpressionFacade.resolveComponentInternal(SearchExpressionFacade.java:422)
at org.primefaces.expression.SearchExpressionFacade.resolveComponentForClient(SearchExpressionFacade.java:200)
at org.primefaces.expression.SearchExpressionFacade.resolveComponentsForClient(SearchExpressionFacade.java:147)
at org.primefaces.util.AjaxRequestBuilder.addExpressions(AjaxRequestBuilder.java:92)
at org.primefaces.util.AjaxRequestBuilder.update(AjaxRequestBuilder.java:85)
at org.primefaces.renderkit.CoreRenderer.buildAjaxRequest(CoreRenderer.java:356)
at org.primefaces.component.commandbutton.CommandButtonRenderer.buildRequest(CommandButtonRenderer.java:123)
...
I allready read following topics:
use-an-el-expression-to-pass-a-component-id-to-a-composite-component-in-jsf
How to find out client ID of component for ajax update/render? Cannot find component with expression "foo" referenced from "bar"
I can't use binding because components are auto generated and too many.
The component already existe because the page haven't changed.
I tried too update only the top/left cell, using its id gaven by the stacktrace but an Exception is still throwed.
It only works when I update the whole form (update=":formControl")... :S
how can I solve it?
PS: I used primefaces but the final terminal is an old company android 2.3.4 with default browser and lots of stuff doesn't work so i have to do it manually.
I fixed this 2 weeks ago in PrimeFaces with some other improvements on the SearchExpressionFramework.
Please try a trunk build - if it doesn't work, create a an issue please + full example.
I'm using PrimeFaces 5.1. I have a TabView component in which the tabs are generated dynamically:
<p:tabView scrollable="true"
id="tabView"
dynamic="true" cache="false"
value="#{reportTabBean.tabs}"
var="tab"
activeIndex="#{reportTabBean.activeTab}">
...
</p:tabView>
The content of a tab is wrapped in a <p:outputPanel>. Inside the panel is a mix of plain HTML <table> tags and <ui:____> components. The tab contents make up a report. Each report has clickable elements created by <p:commandLink> that called a method in the manged bean. Here's is the simplified code:
<p:outputPanel id="bcx-scorecard-panel"
rendered="#{ tab['class'].simpleName eq 'CSAE2EScorecardShowTab'}">
<ui:repeat var="LOB"
value="#{tab.scorecardCSAE2E.getLOBs()}">
<table>
<tbody>
<ui:repeat var="metric"
value="#{tab.scorecardCSAE2E.getMetrics(LOB.filter)}">
<ui:fragment rendered="#{metric.type == 'metric'}">
<tr>
<ui:repeat var="dayNum"
value="#{tab.scorecardCSAE2E.daysInMonthIterator()}">
<td>
<ui:fragment
rendered="#{null != metric.getDataFor(dayNum).value and metric.showDogEar(dayNum)}">
<p:commandLink
immediate="true"
update=":dialogExceptionFillWriteOff, :exceptionFillWriteOffForm"
action="#{exceptionWriteBean.populateExceptionPopup(tab.title, LOB.filter, null, metric, tab.scorecardCSAE2E, dayNum)}"
oncomplete="PF('dlgExceptionFillWriteOff').show()">
#{metric.getDataFor(dayNum).value}
</p:commandLink>
</ui:fragment>
</td>
</ui:repeat>
</tr>
</ui:fragment>
</ui:repeat>
</tbody>
</table>
</ui:repeat>
</p:outputPanel>
Clicking the commandLink brings up a model dialog that displays details about that cell. Each cell represents data for a particular day. The problem is the dialog works only for the last tab. I can click each table cell and it'll display the correct data for that day. When I switch to a different tab and click on cells, the populateExceptionPopup method doesn't get called and instead the dialog shows the last pulled data from the other tab.
My beans are view scoped. I'm not sure if it has anything to do with it, but I'm using CDI beans and annotations. Here's one of the beans.
#Named("reportTabBean")
#ConversationScoped
public class ReportTabBean implements Serializable {
...
}
I have such code in my JSF template:
<h:form>
<table id="users" cellspacing="0">
<a4j:repeat var="person" value="#{personList}">
<tr>
<td class="col1">
<a4j:commandLink
disabled="#{!canCreatePerson}"
styleClass="#{canCreatePerson ? '' : 'inactive_link'}"
action="#{adminPageController.create}"
reRender="user-dialog-region"
timeout="5000"
limitToList="true"
ignoreDupResponses="true"
title="#{canCreatePerson ? messages['edit_user'] : ''}"
onclick="if (!ajaxSubmissionAllowed) {return false;}
ajaxSubmissionAllowed=false;"
oncomplete="ajaxSubmissionAllowed=true;">
<h:outputText id="userName" value="#{person.name}"/>
</a4j:commandLink>
</td>
</tr>
</table>
</h:form>
This perfectly works outside the a4j:repeat tag, but no action performs inside a4j:repeat like it's implemented in my template.
The problem was in SCOPE type of the variable personList, it was CONVERSATION, after I've changed it to PAGE everything works fine.
It's strange that I didn't see any error from SEAM.