TheLQ
TheLQ

Reputation: 15018

Dynamically add and remove components without AJAX?

I have a dynamic form that I'm writing in Wicket with a handful of forms that get duplicated with a "Click here to add more issues" type of button. I've written a very basic (I'm still new to Wicket) AJAXy listener that mostly works, but I can't figure out how to remove or even hide the items in my ListView.

This makes me wonder, is there any way to just have some JS duplicate the form fields? Before I retooled the form with Wicket components I had the Jquery Dynamic Form Plugin duplicating the values. This worked great and was very easy to understand (an important plus). However I can't figure out how this would affect Wicket if I simply used the plugin instead of something like

    //Issue box magic
    final MarkupContainer rowPanel = new WebMarkupContainer("issuesPanel");
    rowPanel.setOutputMarkupId(true);
    form.add(rowPanel);
    ArrayList numIssues = new ArrayList();
    numIssues.add(new Object());
    numIssues.add(new Object());
    numIssues.add(new Object());
    final ListView lv = new ListView("issuesBox", numIssues) {
        @Override
        protected void populateItem(ListItem item) {
            int index = item.getIndex() + 1;

            item.add(new DropDownChoice("issues", combinedIssues));
            item.add(new TextField<String>("note"));
        }
    };
    lv.setReuseItems(true);
    rowPanel.add(lv);
    form.add(new AjaxSubmitLink("addIssue", form) {
        @Override
        public void onSubmit(AjaxRequestTarget target, Form form) {
            lv.getModelObject().add(new Object());
            if (target != null)
                target.add(rowPanel);
        }
    }.setDefaultFormProcessing(false));
    form.add(new AjaxSubmitLink("removeIssue", form) {
        @Override
        public void onSubmit(AjaxRequestTarget target, Form form) {
            //Wicket gets very angry when you remove components, so just hide it (recommended way)
            if (target != null) {
                Component lastObject = (Component)lv.get(lv.getList().size() - 1);
                lastObject.setVisible(false);
                log.debug("Components " + lv.get );
            }

        }
    }.setDefaultFormProcessing(false));

The JQuery plugin is much easier to use, but how can I tell Wicket that there are more fields than it thought there were?

Note I'm also trying to avoid the AJAX call just to add a new issue which in the siltation I'm using the app in might become a problem.

Any suggestions?

Upvotes: 0

Views: 2250

Answers (2)

Andrea Del Bene
Andrea Del Bene

Reputation: 2511

If you invoke removeAll() on ListView after you have modified its model object you should solve your problem. For example

new AjaxSubmitLink("addIssue", form) {
        @Override
        public void onSubmit(AjaxRequestTarget target, Form form) {
            lv.getModelObject().add(new Object());
            lv.removeAll();
            if (target != null)
                target.add(rowPanel);
        }

However I don't know if this could cause problems to form validation, but I think it should be safe.

UPDATE

If you want to apply the same technique for removing link you should write something like this:

new AjaxSubmitLink("removeIssue", form) {
        @Override
        public void onSubmit(AjaxRequestTarget target, Form form) {

            if (target != null) {
                lv.getModelObject().remove(lv.getList().size() - 1);
                lv.removeAll();
                target.add(rowPanel);

            }

        }
    }

However without AJAX this is not possible. The only way is to use JS and on the server side read the request parameters coming from form.

Upvotes: 0

bert
bert

Reputation: 7696

You can't just add form elements in html via ajax. With Wicket, you have a compenent tree in html and Java, and both must match. In the end, Wicket must know what todo with the values when you submit the form.

Not sure I understand your particular requirements, but I guess a similar problem might be that of adding adresses to an person. Here, I would build a AdressEditPanel that contains a form with all the fields that are required for one adress. That Panel would have an PersonAdress (as an example) Object as Model.

On the Person, you would have an Collection of Adresses and use a ListView to render and edit each Adress. In the populateItem() function of the ListView you would add one instance of a AdressEditPanel to the item.

If you need to add an Adress to an person, simply add an entry to the collection of adresses and redisplay the form (I would work with out Ajax first, and once it works do the minimal change required to switch to ajax).

Hope that helps

Upvotes: 3

Related Questions