我有一个表,在每一行中,用户可以单击一个触发书籍可用性检查的链接。所以我有一个commandLink
与action
,它的工作原理,但每次用户点击链接时都会执行此操作。我希望它只能使用一次。此外,我不想在点击后隐藏链接,因为它有隐藏和显示详细信息的onclick
代码。执行操作后是否可以从commandlink中删除action
?
Is it possible to use EL conditional operator in action attribute?中涵盖的答案是您可以解决此问题的方法之一。话虽如此,自JSF 2.2发布以来,还有其他替代方案。虽然删除JSF中的action属性是有问题的(可以通过一些技巧来完成) - 另一个解决方案是使用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>
对于支持bean,这里是一个完整模型的解决方案(使用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()
方法绑定。如您所见,我们只是检查某个“行”是否被视为已点击 - 如果是这种情况,我们将清除当前在该组件上定义的所有actionListeners。实际上,按下按钮时不会调用actionEvent。
虽然上面的解决方案修改了按钮的actionListeners,但它可以被采用并用于其他类型的组件,并且当你想根据某些条件修改组件的某些属性时 - 所以知道这个技巧非常有用。