Apache Wicket AjaxRequestTarget ListView组件未刷新或更新

时间:2018-11-30 12:04:06

标签: java wicket-6

我对apache wicket确实是个新手(从字面上看),我得到了一个任务,需要添加一个项(从引导模态框)后通过ajax刷新表(ListView)。

假设我有一个显示实验室详细信息(房间)的页面和一个显示实验室设备列表的表格。

要添加实验室设备,有一个按钮,单击该按钮时...将显示一个模式框(弹出窗口),用户可以从下拉菜单中选择实验室设备。

添加实验室设备(从弹出模式中)后,该模式将被关闭/隐藏,然后通过ajax刷新表组件。

问题:

用于刷新组件contentDevices的代码似乎不起作用。添加实验室设备后,我可以看到它反映在数据库中。 但是出于未知原因,带有表格显示实验室设备列表的容器没有刷新。

我想在添加/卸下实验室设备后刷新容器/组件contentDevices。组件contentDevices有一个子级,该子级是一个表,用于显示实验室中的设备列表。

现在的问题是,我仍然需要刷新页面(浏览器刷新)以使新添加的实验室设备能够反映出来。

顺便说一句,Device类没有onBeforeRender()。此类的新实例将替换现有的contentDevices

已经有好几天了,但我不知道为什么它没有刷新。如果这只是纯HTML / JS,这真的很容易,但是我对Apache wicket一点都不了解。

page / html结构是这样的:

结构或布局:

<!-- HTML document -->
<Page>
  ...
    <!-- Content section -->
    <div id="content">
      <div id="detailsContainer">
        ...
      </div>
      <div id="devicesContainer">
        ...
        <div id="contentDevices">
          <!-- Other components (ex. table) here that needs to be refreshed after adding/removing device -->
        </div>
        ...
      </div>
      </div>
    </div>
  ...
</Page>

代码:

...

@Override
protected void onSubmit(AjaxRequestTarget target, Form<?> form) {
    super.onSubmit(target, form);

    laboratoryService.addDevice(this.laboratoryModel.getObject(), selectedDevice.getLabel(), selectedDevice.getValue());

    // Refresh laboratory model and update the list of laboratory devices from DB
    Laboratory laboratory = laboratoryService.getLaboratory(this.laboratoryModel.getObject().getId());
    this.laboratoryModel = new Model<>(laboratory);

    // Start: refreshing `contentDevices`
    WebMarkupContainer cContent = (WebMarkupContainer) getPage().get("content");
    WebMarkupContainer devicesContainer = (WebMarkupContainer) cContent.get("devicesContainer");
    Component cDevices = devicesContainer.get("contentDevices");
    cDevices.replaceWith(new Device("contentDevices", getMyPageContext(), this.laboratoryModel));

    devicesContainer.addOrReplace(cDevices);
    cContent.addOrReplace(devicesContainer);

    target.add(cContent);
    // End refreshing `contentDevices`

    // Hide bootstrap modal box
    MyUtil.hideBootstrapModalBox(target, "[data-locator=addDeviceModalBox]");

    // showCustomAlert - show success message
    target.appendJavaScript("showCustomAlert('success', 'Added laboratory device.', true);");
}

...

设备类别:

public class Device extends AbstractMyPagePanel {

    private static final long serialVersionUID = 1L;

    @Autowired
    private LaboratoryService laboratoryService;

    private IModel<Laboratory> laboratoryModel;


    public Device(String id, MyPageContext myPageContext, IModel<Laboratory> laboratoryModel) {
        // `laboratoryModel` is passed until most parent class which is `org.apache.wicket.markup.html.panel.Panel`
        super(id, myPageContext, laboratoryModel);

        this.laboratoryModel = laboratoryModel;

        add(createAddDeviceButton());
        add(new AddDeviceModalBox("addDeviceModalBox", myPageContext, this.laboratoryModel));
        add(createRowsContainer());
        setOutputMarkupId(true);
    }

    private Component createAddDeviceButton() {
        return new WebMarkupContainer("addDeviceButton") {
            private static final long serialVersionUID = 1L;
            @Override
            protected void onConfigure() {
                super.onConfigure();
                setVisible(isAdmin());
            }
        };
    }

    private Component createRowsContainer() {
        WebMarkupContainer result = new WebMarkupContainer("rowsContainer") {
            private static final long serialVersionUID = 1L;
            @Override
            protected void onConfigure() {
                super.onConfigure();
                setVisible(CollectionUtils.isNotEmpty(this.laboratoryModel.getObject().getRoomDevices()));
                setOutputMarkupPlaceholderTag(true);
            }
        };

        // This part here is OK, laboratory model and devices are updated
        System.out.println("\n");
        System.out.println("CREATE-ROW-CONTAINER");
        System.out.println("---------------------------------------------");
        System.out.println("[device-count]: " + this.laboratoryModel.getObject().getRoomDevices().size());
        System.out.println("---------------------------------------------");
        System.out.println("\n");

        System.out.println("\n");
        System.out.println("LABORATORY-DEVICES");
        System.out.println("---------------------------------------------");
        for (LaboratoryDevice device : this.laboratoryModel.getObject().getRoomDevices()) {
            System.out.println("[device]: " + device.getName());
        }
        System.out.println("---------------------------------------------");
        System.out.println("\n");

        // This part here is not OK, `populateItem()` is not called
        // `rows.children` is null, but `rows.data.transientModelObject` is updated and contains the latest added laboratory device
        // Same goes when `add` is used instead of `addOrReplace`, the issue is still there
        result.addOrReplace(new ListView<LaboratoryDevice>("rows", this.laboratoryModel.getObject().getRoomDevices()) {
            private static final long serialVersionUID = 1L;
            @Override
            protected void populateItem(ListItem<LaboratoryDevice> item) {
                LaboratoryDevice device = item.getModelObject();
                item.add(new Label("name", device.getName()));
                item.add(new Label("sn", device.getSn()));
                item.add(new WebMarkupContainer("removeButton").setVisible(isAdmin()));
                item.add(new RemoveLaboratoryDeviceModalBox("removeLaboratoryDeviceModalBox",
                                                  getMyPageContext(), item.getModel()));
            }
        });
        return result;
    }

}

我知道这是非常基本的,但是我找不到任何在网络上真正有用的东西:(

谢谢!

1 个答案:

答案 0 :(得分:0)

您应该检查是否有任何错误:

  • 服务器日志中的错误
  • 浏览器的开发工具控制台中的
  • 错误

我想开发工具中有一个JS错误,说Wicket找不到ID为contentXYZ的HTML元素。如果是这种情况,请确保在实例化cContent.setOutputMarkupId(true)的地方调用cContent,即在页面的构造函数中。

您不需要cDevices.setOutputMarkupId(true),因为您无需将cDevices添加到target

在大多数情况下,在setOutputMarkupId(true)中调用onXYZ(AjaxRequestTarget)太晚了,因为整个页面已经渲染完毕,并且组件/元素需要渲染id属性,稍后再使用当Ajax响应试图找到旧的HTML元素并将其替换为新元素(在onXYZ(AjaxRequestTarget)中创建或更新时)。