在没有JavaScript的情况下在数据列表中动态设置ID

时间:2019-01-10 13:51:14

标签: jsf primefaces

我的Primefaces界面有很大问题。我想遍历列表并显示一些信息以及一个隐藏的编辑字段。

XHTML Primefaces代码片段:

<p:dataList  value="#{datas}" var="data">
<div class="ui-g">
    <div class="ui-g-3">
        <h2>#{data.desc}</h2>
    </div>
    <div class="ui-g-3">
        <p:commandButton operation="edit" disabled="#{data.isLocked()}" actionListener="#{view.edit(data)}"
            style="width:120px;" update="edit_#{data.id}" />
        <p:commandButton operation="delete" actionListener="#{view.delete(data.getId())}" disabled="#{data.isLocked()}"/>           
    </div>
</div>

<!-- works perfectly to set the id -->
<span id="edit_#{data.id}">#{data.desc} #{index}</span>

<!-- doesnt work - maybe of the rendering moment to set the id? -->
<p:panelGrid id="edit_#{data.id}" rendered="#{view.edit}">
    <p:outputLabel for="desc" value="#{msg.text}" />
    <p:inputText id="desc" value="#{view.selectedValue.desc}" />        
</p:panelGrid>

如果要编辑该div,如何设置动态ID到panelGrid以通过commandButton单击来更新它? +如何在编辑时切换div?还是有其他解决方案?我不允许使用JavaScript / jQuery。

非常感谢您!

欢呼声, JohnRamb0r

1 个答案:

答案 0 :(得分:2)

我要说的是您几乎正在与JSF及其代码示例中的JSF一起工作。在向您展示一个有效的示例之前,我想在此介绍一些与良好实践相关的内容:

  • 请勿直接调用方法,请使用属性引用的内置转换。对data.locked的引用将自动转换为对data.isLocked()的调用。最好调用data.locked,因为它将使框架对其进行评估,而不是发送已评估的值。
  • 使用JSF-不反对使用。在示例代码中,有很多不必要的id以及不需要的标签和索引的使用。保持简单并使用框架。直接引用对象而不是引用ID,它可以简化代码并使其更易于在页面上使用。
  • 将动作用作业务逻辑和结果的主要执行者。动作侦听器是预先执行的,可用于拦截或停止执行主动作。因此,它们适合用作执行业务逻辑之前的验证步骤。
  • 标记您的事件。在命名接收用户事件的方法时,最好使用命名约定on<Something>。这样您可以清楚地识别它们。

我为您的代码制作了一个小型示例(使用 Lombok Apache Commons );

@Data
@Named
@ViewScoped
public class DataListViewBackingBean implements Serializable {
    private Entity entity;
    private Entity selectedEntity;
    private List<Entity> dataEntities;

    @PostConstruct
    private void init() {
        dataEntities = new ArrayList<>();

        for (int i = 0; i < 10; i++) {
            dataEntities.add(new Entity(i, RandomUtils.nextBoolean(),
                             RandomStringUtils.randomAlphabetic(30)));
        }
    }

    @Data
    @AllArgsConstructor
    @EqualsAndHashCode(exclude = {"locked","description"})
    public class Entity {
        private int id;
        private boolean locked;
        private String description;
    }

    public void onEdit(Entity entity) {
        selectedEntity = entity;
    }

    public void onDelete(Entity entity) {
        dataEntities.remove(entity);
        selectedEntity = null;
    }
}

上面的代码初始化了一个包含10个实体的数据列表,并用随机数据填充了它。我荣幸地将data更改为entity。当涉及到您的HTML代码时,我觉得需要进行一些清理。 JSF的定义如下所示:

<?xml version="1.0" encoding="UTF-8"?>
<html xmlns="http://www.w3.org/1999/xhtml" xmlns:h="http://java.sun.com/jsf/html" xmlns:p="http://primefaces.org/ui">
    <h:head>
        <title>Data list test</title>
    </h:head>
    <h:body>
        <h:form id="items">
            <p:dataList type="definition" value="#{dataListViewBackingBean.dataEntities}" var="entity">
                <div class="ui-g">
                    <div class="ui-g-8">
                        #{entity.description}
                    </div>
                    <div class="ui-g-4" style="text-align: right">
                        <p:commandButton value="Edit" disabled="#{entity.locked}" action="#{dataListViewBackingBean.onEdit(entity)}" update=":edit" />
                        <p:commandButton value="Delete" disabled="#{entity.locked}" action="#{dataListViewBackingBean.onDelete(entity)}" update="@form :edit" />
                    </div>
                </div>
            </p:dataList>
        </h:form>

        <h:form id="edit">
            <p:outputPanel rendered="#{dataListViewBackingBean.selectedEntity != null}">
                <h1>Editing...</h1>
                <p:inputText placeholder="Description" value="#{dataListViewBackingBean.selectedEntity.description}" />
                <p:commandButton value="Save" update=":items" />
            </p:outputPanel>
        </h:form>
    </h:body>
</html>

请注意如何将编辑div/outputPanel包装在另一个容器(窗体)中。如果我们跳过包装,而是直接在包装的容器上推送更新,则容器的rendered标签将在刷新期间永远不会更新,因此div也不会显示。在这种特殊情况下,这就是为什么在容器外部而不是内部定义表单的原因。

此示例使用@ViewScoped bean,因此只要您停留在页面上,后备数据就应该保持不变。如果您重新加载页面,则将获得带有新实体的新数据集,因为这将重新初始化后备bean并再次调用@PostConstruct

另请参见