Ответ покрыт Можно ли использовать условный оператор EL в атрибуте действия? - это один из способов решения этой проблемы. При этом, начиная с выпуска JSF 2.2 , есть и другие альтернативы. Хотя удаление атрибута действия в JSF проблематично (это можно сделать с помощью некоторых хитростей) - другое решение заключается в использовании actionListeners
вместе с привязкой f:event
, которая связана с событием preValidate
. Это позволяет вам удалить любой из подключенных actionListener, когда вы решите это сделать.
Вот полное решение с прослушивателем событий, который изменяет компонент до его обработки для представления. По сути, вы можете сделать что-то вроде этого;
<?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>
Для базового компонента приведено решение с полной моделью (с использованием 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;
}
}
Ключевые разделы, на которые следует обратить внимание: f:event
и привязка метода onModify()
. Как видите, мы просто проверяем, считается ли определенная «строка» нажатой - если это так, мы очищаем все actionListener, определенные в данный момент для компонента. По сути, при нажатии кнопки не будет вызываться actionEvent.
Хотя вышеприведенное решение изменяет actionListeners кнопки, оно может быть принято и использовано для других типов компонентов, а также когда вы хотите изменить определенные атрибуты компонента на основе какого-либо условия - поэтому очень полезно знать этот прием.