2
votes

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.

1
Could you please try to explain the work flow executed by an end user of the application? In the screenshots it is not clear what the user enters as information, how it is being entered - via the UI or programmatically. I have the feeling that you need to call Form.clearInput() before setting a new model object, in case you do all this programmatically. - martin-g
Ok, I'm trying to explain... - sanluck
- First screenshot - user trying to create a new entity. - He press the green button "Create new service group". Model object of our form sets to new MyObject(). Form rerenders. - User press the "Save" button and validation fails (screenshot №1). - Then, if user choose other object from the tree right after validation fail he can't see nothing in form (object of the form sets correct but the fields are empty but they must be programmatically changed) (screenshot №2). Let me try Form.clearInput() - sanluck
I tried to override onModelChanged() method in the form: @Override protected void onModelChanged() { super.onModelChanged(); this.clearInput(); } but it didn't helped... - sanluck
Hmm I think it's incorrect to override this method... Sorry - sanluck

1 Answers

4
votes

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.