Search code examples
javawicketwicket-6

Wicket Form loads empty values after validation fails


We have a trouble in our wicket 6 project. We have a form which is loading via AJAX.

When our form fails validation we can't load other object into the model correcly (fields that have failed are empty).

I'm trying to create new object (my modelobject value = new MyObject()) and validation fails :

enter image description here

Then if I choose already created object from the tree on the left side I can see empty fields :

enter image description here

But really this object has all the fields setted :

enter image description here

Form markup:

<wicket:panel>
        <div wicket:id="feedback"></div>
        <form wicket:id="form" role="form" class="form-horizontal">
            <div class="form-group">
                <label wicket:for="shortName" class="control-label col-sm-4"><wicket:message key="shortName"></wicket:message></label>
                <div class="col-sm-8">
                    <input type="text" class="form-control" wicket:id="shortName" />
                </div>
            </div>
            <div class="form-group">
                <label wicket:for="fullName" class="control-label col-sm-4"><wicket:message key="fullName"></wicket:message></label>
                <div class="col-sm-8">
                    <input type="text" class="form-control" wicket:id="fullName" />
                </div>
            </div>
            <div class="form-group">
                <label wicket:for="parentServiceGroup" class="control-label col-sm-4"><wicket:message key="parentServiceGroup"></wicket:message></label>
                <div class="col-sm-8">
                    <select type="text" class="form-control width-abs" wicket:id="parentServiceGroup"></select>
                </div>
            </div>
            <div class="form-group">
                <label wicket:for="status" class="control-label col-sm-4"><wicket:message key="status"></wicket:message></label>
                <div class="col-sm-8">
                    <select class="form-control width-abs" wicket:id="status"></select>
                </div>
            </div>
            <div>
                <a wicket:id="save" class="btn btn-primary"></a>
                <a wicket:id="cancel" class="btn btn-default"></a>
            </div>
        </form>
    </wicket:panel>

Form code :

@Override
protected void onInitialize() {
    super.onInitialize();
    add(new MiraFeedbackPanel("feedback"));
    final Form form = new Form("form", CompoundPropertyModel.of(getDefaultModel())) {
        @Override
        protected void onError() {
            super.onError(); 
            this.updateFormComponentModels();
        }

    };
    add(form);
    form.add(new TextField("shortName").setRequired(true));
    form.add(new TextField("fullName"));
    form.add(new DropDownChoice("status", Arrays.asList(CommonStatus.values()), 
            new ChoiceRenderer<CommonStatus>("name")).setRequired(true));
    form.add(new ServiceGroupDropDownChoice("parentServiceGroup", getServiceGroupModelObject()));
    form.add(new AjaxSubmitLabeledLink("save", "Save", form) {
        @Override
        protected void onError(AjaxRequestTarget target, Form<?> form) {
            super.onError();
            error(getString("savingError"));
            target.add(ServiceGroupEditPanel.this.get("feedback"));
        }

        @Override
        protected void onSubmit(AjaxRequestTarget target, Form<?> form) {
            getServiceGroupModelObject().setDateCreated(new Date());
            getServiceGroupModelObject().setWorkerCreated(UserSession.get().getWorker());
            getServiceGroupModelObject().setDateModification(new Date());
            getServiceGroupModelObject().setWorkerModification(UserSession.get().getWorker());
            DAOService.ejbCommonBean().saveEntity(getServiceGroupModelObject());
            info(getString("serviceGroupSaved"));
            target.add(ServiceGroupEditPanel.this.get("feedback"));
            target.add(ServiceGroupEditPanel.this.getParent().getParent()
                    .get("serviceGroupsTree"));
        }
    });
    form.add(new AjaxLabeledLink("cancel", "Cancel") {
        @Override
        public void onClick(AjaxRequestTarget target) {
            getServiceGroupModel().setObject(null);
            target.add(ServiceGroupEditPanel.this.getParent().getParent()
                    .get("serviceGroupsTree"));
            target.add(ServiceGroupEditPanel.this.getParent().getParent()
                    .get("serviceNotSet"));
            target.add(ServiceGroupEditPanel.this.getParent().getParent()
                    .get("selectedServiceGroup"));
            target.add(ServiceGroupEditPanel.this.getParent());
        }
    });
}

We tried the workaround from this issue : Apache wicket: how to update model after validation error but it didn't helped.

UPD: Code of tree from where I'm trying to update model :

add(new DefaultNestedTree<ServiceGroup>("serviceGroupsTree", new ServiceGroupsTreeProvider()) {

        @Override
        protected Component newContentComponent(String id, IModel<ServiceGroup> node) {
            return new Folder<ServiceGroup>(id, this, node) {
                @Override
                protected Component newLabelComponent(String id, IModel<ServiceGroup> model) {
                    return new Label(id, PropertyModel.of(model, "shortName"));
                }

                @Override
                protected MarkupContainer newLinkComponent(String id, final IModel<ServiceGroup> model) {
                    return new AjaxLink(id, model) {
                        @Override
                        public void onClick(AjaxRequestTarget target) {
                            serviceGroupModel.setObject(DAOService.ejbCommonBean()
                                    .getEntityFullFetch(
                                            ServiceGroup.class, 
                                            model.getObject().getUidservicegroup()
                                    ));
                            target.add(ServiceGroupListPage.this.get("selectedServiceGroup"));
                            target.add(ServiceGroupListPage.this.get("serviceNotSet"));
                            target.add(ServiceGroupListPage.this.get("tabs"));
                            ((ServiceGroupEditPanel)editPanelTab.getPanel("editTab")).onModelObjectChanged(target);
                        }
                    };
                }
            };
        }
    }

Our form added to the AjaxTabbedPanel :

final ServiceGroupEditPanelTab editPanelTab = new ServiceGroupEditPanelTab("editTab", serviceGroupModel);
    List<ITab> tabsList = new ArrayList<>();
    tabsList.add(editPanelTab);
    tabsList.add(new ServiceGroupServicesPanelTab("servicesTab", serviceGroupModel));

    final AjaxTabbedPanel tabs = new AjaxBootstrapTabbedPanel("tabs", tabsList);
    tabs.setSelectedTab(0);
    add(tabs);

UPD2: I've added the sample project to Github to show my problem. In README.md there are steps to reproduce the error.


Solution

  • If you're just swapping the object in your model, all your form components will still hold the previous raw input.

    Call Form#clearInput() after you've changed your model object, i.e. after you've chosen a different entity from your tree.