I would like to use PrimeFaces Selectors to process all input components in a certain group, which includes several p:rating fields.
I minimized my use case to, XHTML:
<h:form>
<h:panelGroup styleClass="myGroup">
<p:rating value="#{myBean.rating}"/>
<p:commandButton value="Save"
process="#(.myGroup :input)"
action="#{myBean.save()}"/>
</h:panelGroup>
</h:form>
Bean:
#Named
#ViewScoped
public class MyBean implements Serializable {
private Integer rating; // Getter and setter are present
public void save() {
System.out.println("Rating: " + rating);
}
}
With the above selector the rating is not processed. If I change the component to p:inputText, it is working. If I remove the process attribute, it is also working. I assume this has to do with the hidden input p:rating is using for its value.
My question: can you create a PrimeFaces selector which includes the inputs of components with hidden input fields?
:hidden is a special Jquery selector not part of CSS.
See: https://api.jquery.com/hidden-selector/
So change your selector to:
#(.myGroup :input :hidden)
However I doubt it's a big deal in your case but make sure to read the "Additional Notes" section in the jQuery :hidden documentation.
An alternative which works as well in your case is using p:fragment:
<h:form>
<p:fragment>
<p:rating value="#{myBean.rating}"/>
<p:commandButton value="Save"
action="#{myBean.save()}"/>
</p:fragment>
</h:form>
Related
I tried to find this in a lot of places, but it is not clearly written anywhere. For example in this documentation the usage is given only for JSP but not for JSF.
Example used in the documentation :
<textarea name="text">
<b><%= Encode.forHtmlContent(UNTRUSTED) %></b>
</textarea>
I need something similar for <h:outputText ... escape='true'> (escape attribute is not enough for Cross Site Scripting : Poor Validation).
Just use standard converter.
<h:outputText value="#{value}" escape="false">
<f:converter converterId="unsafeHTMLConverter" />
</h:outputText>
With some custom work like:
#FacesConverter("unsafeHTMLConverter")
public class UnsafeHTMLConverter implements Converter {
PolicyFactory policy = // your fancy policy
// (...)
#Override
public String getAsString(FacesContext context, UIComponent component, Object untrustedHTML) {
return policy.sanitize((String) untrustedHTML);
}
}
since fileLimit doesn't exist in primefaces 3.4 anymore I'm trying a work around implementing a validator, the problem is that the method validate is never invoked. That's my Validator:
#FacesValidator(value ="fileLimitValidator")
public class FileLimitValidator implements Validator {
#Override
public void validate(final FacesContext context, final UIComponent component,
final Object value) throws ValidatorException {
final String fileLimit = (String)component.getAttributes().get("fileLimit");
final String size = (String)component.getAttributes().get("size");
if (fileLimit!=null && size!=null) {
if (Integer.valueOf(size) >= Integer.valueOf(fileLimit)) {
FacesUtils.throwErrorExceptionFromComponent(component,"fichero_confidencialidad_error");
}
}
}
}
and in my facelet I've tried:
<p:fileUpload id="#{id}FileUpload"
fileUploadListener="#{bean[metodoTratarFichero]}" mode="advanced"
multiple="true" allowTypes="#{allowTypes}" showButtons="false"
update="#{id}ListaDocs #{id}MsgError" auto="true"
label="#{fileuploadmsg.label_boton}"
invalidFileMessage="#{fileuploadmsg.tipo_incorrecto}" >
<f:validator validatorId="fileLimitValidator"/>
<f:attribute name="fileLimit" value="#{fileLimit}"/>
<f:attribute name="size" value="#{listaDocumentos.size}"/>
</p:fileUpload>
and:
<p:fileUpload id="#{id}FileUpload"
fileUploadListener="#{bean[metodoTratarFichero]}" mode="advanced"
multiple="true" allowTypes="#{allowTypes}" showButtons="false"
update="#{id}ListaDocs #{id}MsgError" auto="true"
label="#{fileuploadmsg.label_boton}"
invalidFileMessage="#{fileuploadmsg.tipo_incorrecto}"
validator="fileLimitValidator">
<f:attribute name="fileLimit" value="#{fileLimit}"/>
<f:attribute name="size" value="#{listaDocumentos.size}"/>
</p:fileUpload>
and:
<p:fileUpload id="#{id}FileUpload"
fileUploadListener="#{bean[metodoTratarFichero]}" mode="advanced"
multiple="true" allowTypes="#{allowTypes}" showButtons="false"
update="#{id}ListaDocs #{id}MsgError" auto="true"
label="#{fileuploadmsg.label_boton}"
invalidFileMessage="#{fileuploadmsg.tipo_incorrecto}"
validator="#{fileLimitValidator}">
<f:attribute name="fileLimit" value="#{fileLimit}"/>
<f:attribute name="size" value="#{listaDocumentos.size}"/>
</p:fileUpload>
and:
<p:fileUpload id="#{id}FileUpload"
fileUploadListener="#{bean[metodoTratarFichero]}" mode="advanced"
multiple="true" allowTypes="#{allowTypes}" showButtons="false"
update="#{id}ListaDocs #{id}MsgError" auto="true"
label="#{fileuploadmsg.label_boton}"
invalidFileMessage="#{fileuploadmsg.tipo_incorrecto}"
validator="#{fileLimitValidator.validate}">
<f:attribute name="fileLimit" value="#{fileLimit}"/>
<f:attribute name="size" value="#{listaDocumentos.size}"/>
</p:fileUpload>
but the validate method is never called. What is the correct way to do it?
According to the FileUpload and FileUploadRenderer source code, the validator is only invoked when mode="simple" is been used (note: this in turn requires ajax="false" on command). The advanced mode will namely not set the uploaded file as component's submitted value, causing it to remain null until the listener method is invoked. As long as the submitted value is null, the validators are not invoked.
I'm not sure if this is intentional. Theoretically, it should be possible to set UploadedFile as submitted value and have the validator to rely on it. You might want to create an enhancement report at PrimeFaces issue tracker.
In the meanwhile, in spite of it being a poor practice, your best bet is really performing the validation in fileUploadListener method. You can just trigger validation failure add faces messages through the FacesContext like follows:
if (fail) {
context.validationFailed();
context.addMessage(event.getComponent().getClientId(context), new FacesMessage(
FacesMessage.SEVERITY_ERROR, messageSummary, messageDetail));
}
Otherwise, you'd need to create a custom renderer for the <p:fileUpload> which sets the submitted value during the decode() (I however don't guarantee that it would work in practice, you'll maybe stumble upon a peculiar problem which may turn out to be the reason why PrimeFaces didn't initially implement it like that).
By the way, your first and second validator attempt are correct. The third attempt works only if you used #ManagedBean instead of #FacesValidator (which is often done when injection of an #EJB is mandatory — which isn't possible in a #FacesValidator). The fourth attempt is invalid.
For validating a required primefaces file upload in mode advanced (ajax) it is possible to use this:
<f:metadata>
<f:event listener="#{bean.processValidations()}" type="postValidate" />
</f:metadata>
Where the implementation of the bean.processValidations() method would be something along the lines of:
public void processValidations() {
FacesContext context = FacesContext.getCurrentInstance();
UIInput fileUploadComponent = fileUploadsBean.getFileUploadComponent();
if (fileUploadComponent!=null && !isFileUploaded()) {
fileUploadComponent.setValid(false);
context.addMessage(fileUploadComponent.getClientId(context), new FacesMessage(FacesMessage.SEVERITY_ERROR, messageSummary, messageDetail));
context.validationFailed();
}
}
Where fileUploadsBean would be a REQUEST scoped CDI bean (won't work with standard JSF ManagedBeans) which you inject to your bean which has the processValidations() method defined, the method fileUploadsBean.getFileUploadComponent() returns the primefaces file upload component (you will use <p:fileUpload binding="#{fileUploadsBean.fileUploadComponent}" ...> for that). The method isFileUploaded() will determine if the file has been uploaded or not (probably just a null check on a member variable which you fill from fileUploadListener).
If you want to highlight the file upload button you can of course conditionally add a styleClass which you can then use for adding a red border for example.
styleClass="#{fileUploadsBean.fileUploadComponent.valid ? '' : 'validationFailed'}"
As a result the validation failed message for the primefaces file upload will be displayed along with all other jsf validation messages. You might have problem with maintaining order of the validation messages (will be always at the end), but it still beats displaying the failed upload file validation after user dealt with all the standard jsf validation messages from different fields and your action in a backing bean has been finally reached.
The first pic shows the selection of two checkboxes in a datatable. There were two rows of the datatable shown. At the first checkbox of the row you can see the brackets of the selection list. The only action were the selection of the checkboxes. Nothing more.
Now, when I reload the page or click on the button at the botton, the state changes like in the second pic.
Only the selection of the last row checkboxes are in the selection list.
So I m thinking about, if it is a problem with the selection list and its managed bean.
I tried a changelistener on the checkbox but I cant get the status of the checkbox, checked or unchecked.
So I removed it again.
<p:datatable>...
<p:rowExpansion>#{pathSearch.selectedSignalList1}
<p:selectManyCheckbox id="signalSel" value="#{pathSearch.selectedSignalList1}">
<p:ajax listener="#{pathSearch.changeSignalListener1}" />
<f:selectItems value="#{pathDistSel.availableSignalList}"
var="sig" itemValue="#{sig.label}___#{sig.idS}" itemLabel="#{sig.label}" />
</p:selectManyCheckbox>
</p:rowExpansion>
Bean snippet
#ManagedBean
#SessionScoped
public class PathSearch implements Serializable {
private List<Signal> selectedSignalList1;
getter, setter...
}
I would be happy, if someone has an idea, where my mistake in thinking is. Perhaps you have an example of something like this.
By using
<p:selectManyCheckbox id="signalSel" value="#{pathSearch.selectedSignalList1}">
<p:ajax listener="#{pathSearch.changeSignalListener1}" />
<f:selectItems value="#{pathDistSel.availableSignalList}"
var="sig" itemValue="#{sig.label}___#{sig.idS}" itemLabel="#{sig.label}" />
</p:selectManyCheckbox>
In the row expansion, the selection list in each row points to the same property, selectedSignalList1. You need to use a list/array there with the row index as a key, or a hashmap and a business key. So something like
<p:datatable ... rowIndex="signalIndex">
<p:selectManyCheckbox id="signalSel" value="#{pathSearch.selectedSignalList[signalIndex]}">
<p:ajax listener="#{pathSearch.changeSignalListener}" />
<f:selectItems value="#{pathDistSel.availableSignalList}"
var="sig" itemValue="#{sig.label}___#{sig.idS}" itemLabel="#{sig.label}" />
</p:selectManyCheckbox>
</datatable>
And in the bean
#ManagedBean
#SessionScoped
public class PathSearch implements Serializable {
private ArrayList<List<Signal>> selectedSignalList = new ArrayList<>();
getter, setter...
}
This way, each p:selectManyCheckbox in the p:rowexpansion has its own list backing the local selection
What you do on submission and how to aggregate or restore when you need to load the submitted data e.g. from a database and show it on screen is up to you to implement.
I use primefaces,
my table has more than 75 column,
how to do when I want to copy row and paste it in the same table (of course change the PK after)
you can use the <p:hotkey> (to capture your copy and paste) along with the selectionMode attribute of <p:dataTable>
you can try:
<h:form>
<p:hotkey bind="ctrl+c" actionListener="#{Bean.copy}"/>
<p:hotkey bind="ctrl+s" actionListener="#{Bean.paste}"/>
<p:dataTable id="dceTable" value="#{Bean.list}"
var="row" selection="#{Bean.selection}"
rowKey="#{row.seqNo}" >
<p:column selectionMode="multiple" style="width:30px;text-align:center" />
... insert your columns here
</dataTable>
</h:form>
and your backing bean:
#Named("DCEBean")
#ViewScoped
public class Bean implements Serializable {
public void copy(){
// to copying codes like change PK
}
public void paste(){
// insert in your copied rows
}
}
You can't out of the box. Only thing I can think of is to create a context menu and/or intercept the ctrl-v/c keys and call some backing bean methods that all does this for you. But that would be to complex of a solution to create for you.
thank for all answers
but i have a little solution:
in the "list.xhtml" file and at context menu panel add the line:
<p:menuitem value="Copy" onclick="document.getElementById('CustomerListForm:copyButton').click();" icon="ui-icon-copy"/>
at the end of the file with other buttom add the line:
<p:commandButton id="copyButton" style="visibility: hidden; icon="ui-icon-copy" value="Copy" update=":CustomerCreateForm" oncomplete="PF('CustomerCreateDialog').show()"/>
for more click here
I'm trying the following:
labelconfig.xhtml:
<h:form id="ok">
<h:commandButton value="click">
<f:ajax event="click" listener="#{canvasController.oeps}" />
</h:commandButton>
</h:form>
And I'm trying to get it here:
CanvasController.java
#ManagedBean(name = "canvasController")
#SessionScoped
public class CanvasController
public void oeps(AjaxBehaviorEvent event) {
JOptionPane.showMessageDialog(null, "SUCCES3");
}
}
But when I click the button, I get:
serverError: class java.awt.HeadlessException
How is this caused and how can I solve it?
You are trying to call Swing from server application without any desktop GUI. Instead of JOptionPane use logger or FacesContext.addMessage to get feedback. If for some reason you do want to control Swing app through JSF make sure DISPLAY etc are set but then I suggest rephrasing your question.