I have a picklist component (Primefaces 6.x ) in one of my pages. The picklist has a "transfer" event listener as shown in the showcase:
<p:ajax event="transfer" listener="#{pickListView.onTransfer}" update="msg" />
This works pretty well and my method is called every time i add or remove items from the target list.
My question is if it is possible to trigger the event handler only when adding items in the target list or if there is a way to catch the remove from target action in my method and ignore all validations that i am doing in bean method.
There is an advantage to source being open and having a good IDE for code completion. Both can show that the TransferEvent.java has isAdd() and isRemove() methods. These can easily be used to differentiate in an eventHandler which one is actually used.
public void onTransfer(TransferEvent event) {
if (event.isAdd()) {
// Do actual work
}
}
Related
let's say we have two types of events that will be directed to the same method as mentioned in the below example
<p:ajax event="cellEdit" listener="#{bean.eventype}"/>
<p:ajax event="change" listener="#{bean.eventype}"/>
and here is the bean method for example
public void eventype(){
println("");
}
The question is, is it possible if I want to identify which value came from which events in eventype method?
Is it possible to differentiate both mentioned events in eventype method?
Edited:
I did try to add eventype(AjaxBehaviorEvent event) and use event.getSource() but it seems like am just getting the source details like org.inputtext.component#something.
The type of event is posted in the request in order for the component being able to decode it to trigger the correct event. The parameter name is javax.faces.behavior.event, which you can get like:
String eventType = FacesContext.getCurrentInstance()
.getExternalContext()
.getRequestParameterMap()
.get("javax.faces.behavior.event");
This is implemented in PrimeFaces like:
https://github.com/primefaces/primefaces/blob/042b5a14116cd4a279a114883a8575e0788494b8/primefaces/src/main/java/org/primefaces/util/ComponentUtils.java#L197-L224
Note that you can also use the PrimeFaces constant Constants.RequestParams.PARTIAL_BEHAVIOR_EVENT_PARAM in your code instead of hardcoding "javax.faces.behavior.event".
I've been working on CRUD application, and I need to export data from database to csv file.
In order to export, I had to disable ajax, in a manner shown in following code:
<p:commandButton value="Export" ajax="false" action="myController.export"/>
In the method invoked, I create the file and download it via OmniFaces utility method:
Faces.sendFile(file, true);
Using the same method, I check if there actually is any data, and if there isn't any data, warning dialog is shown:
RequestContext.getCurrentInstance().showMessageInDialog(new FacesMessage(FacesMessage.SEVERITY_WARN, "Warning!", "No available data for export."));
Now, while all of this does work as intended, the problem is that because ajax is disabled, dialog cannot be dynamically shown, and page is reloaded. If ajax is enabled, dialog is shown dynamically, but file download doesn't start.
I've been trying to work around this issue, by using Monitor download, or by force clicking second button, but so far I haven't made any progress on the matter.
Is there any generally acceptable way of solving issues like this one?
Is there any generally acceptable way of solving issues like this one?
You basically want to fire an ajax request first and in its oncomplete check if it's successful, and then trigger a synchronous request to download the file (note that you can't download files with ajax). You could make use of FacesContext#validationFailed() (or OmniFaces Faces.validationFailed()) to mark the validation fail state which is available via args object which PrimeFaces injects in the oncomplete function context (note that ajax related attributes such as oncomplete don't work when ajax is disabled).
Something like this:
<p:commandButton
value="Export"
action="#{bean.export}"
oncomplete="if (args && !args.validationFailed) PF('download').jq.click()" />
<p:commandButton
widgetVar="download"
styleClass="ui-helper-hidden"
action="#{bean.download}" ajax="false" />
public void export() {
// Prepare file locally.
if (fail) {
// Show message your way and then set validation failed as below.
Faces.validationFailed();
}
}
public void download() throws IOException {
Faces.sendFile(file, true);
// Delete local file afterwards?
}
Note that a hidden <p:commandButton> is being used instead of <p:remoteCommand> as the latter doesn't support ajax="false".
I have a list of items that are being displayed using a h:datatable like so:
<p:dataTable value="#{myBean.instructorsList}" var="ins">
<p:column headerText="Name">
<h:inputText value="#{ins.name}"/>
</p:column>
</p:dataTable>
My spec is that I cannot allow a instructor to have the same name as another insturctor. So I need to have access to all the entire instructorList when it is submitted. I have attempted to validate using a postValidate f:event however due to the JSF lifecycle it does not update the model values till after the postValidation phase.
My attempt
<f:event listener="#{myBean.myMethod}" type="postValidate" />
Backing code
private List<instructors> instructorsList;
public void myMethod(ComponentSystemEvent event) {
// Attempting to use the instructorsList with new values. However, this
// is at the wrong stage
}
How would I write a validator to accomplish checking for duplicate instructor names?
Within a listener, use the getSubmittedValue method on HtmlInputText to pull the value straight off the component. Also, postValidate is semantically late to call problems on the validation process. Use the preValidate method instead. Altogether, you should have
public void myMethod(ComponentSystemEvent event) {
HtmlInputText txtBox = (HtmlInputText)event.getComponent();
String theValue = txtBox.getSubmittedValue().toString(); //the value in the textbox
//based on the outcome of your validation, you also want to do the following
FacesContext.getCurrentInstance().setValidationFailed(); //flag the entire request as failing validation
txtBox.setValid(false); //mark the component as failing validation
}
EDIT: This approach is heavily hinged on the premise that your users will be submitting only one row at a time. In the case where the entire table/column is being submitted in one request, you'll find that evaluating each input field on by one doesn't do much to prevent race conditions; you should be looking toward cross-field validation instead.
EDIT 2: I was mistaken, you cannot have race conditions when the event listener is being called. The listener is executed for each row, sequentially. This allows you to safely check each row (perhaps against a Map, for duplicates), without worrying about race conditions.
This has to be a dumb question, but I can't seem to find the right keywords to google on: I have an action listener that can receive an event from any one of multiple checkboxes that were all generated from the same line of jsp in a dataTable. How can I tell from the action listener which one issued the event?
In particular, I need the index of the component so I can map it to an ordered list in the model. I know I can get the UIComponent object, and from there I can get the client ID of the component. And knowing that the client ID has the component's index embedded in it, yes I could do the sleazy thing, and parse the index from the client ID. But I know that would be a horrible, fragile and unmaintainable hack.
What's the right way to do this?
After an initial search, I think this could help you.
http://illegalargumentexception.blogspot.com/2009/02/jsf-working-with-component-ids.html
Have you tried to use f:param in addition to the checkbox values to pass custom parameters, so that would be more cleaner than working with ID's to manipulate business logic. ID.
Using the DataTables var attribute, you should be able to do this
<h:dataTable ... var="currentRow">
....
<h:selectBooleanCheckbox ... actionListener="#{blah.doThis}">
<f:attribute name="curRec" value="#{currentRow}" />
</h:selectBooleanCheckbox>
bean:
public void doThis(ActionEvent ae)
{
TreeMap myMap = (TreeMap)ae.getComponent().getAttributes().get("curRec");
...
}
Edit: The binding variable of your datatable should have the method getRowIndex();. That should give you the index of the record that caused the event in the table. I'm referencing an ICEfaces project, so I apologize if that isn't correct. Let me know, thx.
I have some code generated by netbeans wizard 'JSF pages from entity classes'.
For those who don't use netbeans I will briefly describe what the wizard does.
It creates a JSF page List.xhtml which contains a datatable with a fixed size of ten rows and two commandlinks for scrolling its content (prev 10 and next 10).
The JSF page uses a managedbean with session scope and the above mentioned commandlinks return the String 'List'.
If I change the managed bean scope to #viewscoped it is re-created every time I push a commandlink. According to me it is a weird behavior because the view actually doesn't change (it always List.xhtml ) and I would have expected a smarted view scope mechanism.
I then changed the action associated to the commandlinks with a new one which does the same things but returns void. Now the #viewscope mechanism works well but I'm not sure it is correct to use an action method with a signature like this
public void doSomething()
// instead of
public String doSomething()
My concern is that a different JSF implementation can act in an impredictable way with that kind of actions.
Thanks
Filippo
What do you return in public String doSomething()?
If you return null (or an empty String) it should not re-create the view.
If you return a navigation case then the view is re-created, regardless whether it is the same that you are currently in.