I have a table and in each row user can click on a link which triggers book availability check. So I have a commandLink
with action
and it works, but this action is executed every time user clicks on a link. I want it to be available only once. Also I don't want to hide link after click as it has onclick
code which hides and shows details. Is it possible to remove action
from commandlink after executing action?

- 287
- 1
- 5
- 16
-
Tried updating them and set disabled is true? – Jasper de Vries Mar 06 '19 at 20:19
-
Right. I'd recommend to read https://stackoverflow.com/questions/25339056/understanding-primefaces-process-update-and-jsf-fajax-execute-render-attributes – Jasper de Vries Mar 07 '19 at 10:52
-
So I think OP should switch between two buttons – Kukeltje Mar 07 '19 at 12:02
-
1Or dynamically 'switch' the `type="..."` to button... Then it will ignore the action and become a pure client-side javascript button – Kukeltje Mar 07 '19 at 12:05
-
@Kukeltje if you exclude the link from being processed / executed after the first click? – Jasper de Vries Mar 07 '19 at 12:05
-
But then it will still do an unnecessary ajax call – Kukeltje Mar 07 '19 at 12:06
-
you want do that for view page or for specific user ?? – yali Mar 07 '19 at 13:10
-
I'm experimenting with switching between 2 links now, similarly to https://stackoverflow.com/questions/10473743/is-it-possible-to-use-el-conditional-operator-in-action-attribute – J.Doe Mar 07 '19 at 16:36
1 Answers
The answer covered in Is it possible to use EL conditional operator in action attribute? is one of the ways that you can solve this. With that being said, since the release of JSF 2.2, there are also other alternatives. While removing the action attribute in JSF is problematic (it can be done with some trickery) - another solution is to use actionListeners
together with an f:event
binding that is connected to the preValidate
event. This allows you to remove any of the connected actionListeners whenever you choose to do so.
Here is a complete solution with an event listener that modifies the component prior to it being processed for the view. Basically, you can do something like this;
<?xml version="1.0" encoding="UTF-8"?>
<html xmlns="http://www.w3.org/1999/xhtml" xmlns:h="http://java.sun.com/jsf/html"
xmlns:f="http://java.sun.com/jsf/core">
<h:head>
<title>Dynamic action demo</title>
</h:head>
<h:body>
<h:form>
<h:dataTable var="row" value="#{removeActionBackingBean.rows}">
<h:column>#{row.primaryColumn}</h:column>
<h:column>#{row.hasBeenClicked}</h:column>
<h:column>
<h:commandButton actionListener="#{removeActionBackingBean.onPressed(row)}">
<f:attribute name="clicked" value="#{row.hasBeenClicked}"/>
<f:event listener="#{removeActionBackingBean.onModify}" type="preValidate" />
<f:ajax event="click" render="@form" />
</h:commandButton>
</h:column>
</h:dataTable>
</h:form>
</h:body>
</html>
For the backing bean, here is a solution with a complete model (using Lombok);
@Data
@Named
@ViewScoped
public class RemoveActionBackingBean implements Serializable {
private List<Row> rows;
@PostConstruct
private void init() {
rows = new ArrayList<>();
for (int i = 0; i < 10; i++) {
rows.add(new Row(RandomStringUtils.randomAscii(10)));
}
}
public void onPressed(Row row) {
row.hasBeenClicked = true;
System.out.println(String.format("'%s' has been pressed!", row.primaryColumn));
}
public void onModify(ComponentSystemEvent event) {
final boolean isRowClicked = (boolean) event.getComponent().getAttributes().get("clicked");
if (isRowClicked) {
for (ActionListener al : ((UICommand) event.getComponent()).getActionListeners()) {
((UICommand) event.getComponent()).removeActionListener(al);
}
}
}
@Data
@RequiredArgsConstructor
public class Row {
private @NonNull String primaryColumn;
private boolean hasBeenClicked;
}
}
The key sections to look at is f:event
and the onModify()
method binding. As you can see, we simply check if a certain "row" is considered as clicked - if this is the case, we clear all the actionListeners currently defined on the component. Effectively, there will be no actionEvent called when the button is pressed.
While the above solution modifies the actionListeners of a button, it can be adopted and used for other types of components and when you want to modify certain attributes of a component based on some condition - so it's extremely useful to know this trick.

- 2,271
- 9
- 26