I want to code a custom form component that allows users to edit the set of tags of some object. When constructed, the component receives a model for the current set of tags. The user can then edit this set using AJAX Add button and Remove links:

  Current tags: Foo (x), Bar (x)
  Add tag: [text field] Add

I have implemented the component as a FormComponentPanel<List<String>>, with AjaxLink's to realize the remove links (x) and with an AjaxSubmitLink for
the Add button.

The remove links work but the Add button's onSubmit() always fails with a NullPointerException when it tries to get the model object, getModelObject(), of the enclosing FormComponentPanel. Does anybody see what I am doing wrong?

I attach the complete source (heavily cut down).

Thank you in advance for any hint or guidance, and sorry for the lenghty post,
Kaspar

// File Test.html
<html>
<body>
<form wicket:id="form">
 <div wicket:id="selector"></div>
 <input type="submit" value="Submit"/>
</form>
</body>
</html>

// File Test.java
package org.test;

import java.util.ArrayList;
import java.util.List;

import org.apache.wicket.markup.html.WebPage;
import org.apache.wicket.markup.html.form.Form;
import org.apache.wicket.model.IModel;
import org.apache.wicket.model.Model;

public class Test extends WebPage
{

  public Test()
  {
    super();

    final Form form = new Form("form");
    add(form);

    List<String> initialTags = new ArrayList<String>();
    initialTags.add("Foo");

    IModel<List<String>> tagsModel = Model.of(initialTags);
    form.add(new TagSelector("selector", tagsModel));
  }
}

// File TagSelector.html
<html xmlns:wicket>
<wicket:panel>
   <!-- Feedback -->
   <div wicket:id="feedback"></div>

   <!-- Currently selected tags -->
   Tags:
   <ul>
<li wicket:id="tag"><wicket:container wicket:id="tag-name"/> <a href="#" wicket:id="remove">remove</a></li>
   </ul>

   <!-- Field and button to add tag -->
Add: <input type="text" wicket:id="input"/> <input value="Add" wicket:id="add-button" type="submit"/>
</wicket:panel>
</html>

// File TagSelector.java
package org.test;

import java.util.Arrays;
import java.util.Iterator;
import java.util.List;

import org.apache.commons.lang.StringEscapeUtils;
import org.apache.wicket.ajax.AjaxRequestTarget;
import org.apache.wicket.ajax.markup.html.AjaxLink;
import org.apache.wicket.ajax.markup.html.form.AjaxSubmitLink;
import org .apache .wicket.extensions.ajax.markup.html.autocomplete.AutoCompleteTextField;
import org.apache.wicket.markup.html.basic.Label;
import org.apache.wicket.markup.html.form.Form;
import org.apache.wicket.markup.html.form.FormComponentPanel;
import org.apache.wicket.markup.html.list.ListItem;
import org.apache.wicket.markup.html.list.ListView;
import org.apache.wicket.markup.html.panel.FeedbackPanel;
import org.apache.wicket.model.IModel;
import org.apache.wicket.model.Model;

public class TagSelector extends FormComponentPanel<List<String>>
{
  private final static String[] DUMMY_TAGS_ARRAY = {
      "Foo", "Bar", "Foobar"
  };
private final static List<String> DUMMY_TAGS = Arrays.asList(DUMMY_TAGS_ARRAY);

  public TagSelector(String id, IModel<List<String>> model)
  {
    super(id, model);

    setOutputMarkupId(true);
    add(new FeedbackPanel("feedback"));
    add(new ListView<String>("tag", model)
    {
      @Override
      protected void populateItem(ListItem<String> item)
      {
        final String tagName = item.getModelObject();
        item.add(new Label("tag-name", tagName));
        item.add(new AjaxLink("remove")
        {
          @Override
          public void onClick(AjaxRequestTarget target)
          {
            // Remove tag from current selection
            TagSelector.this.getModelObject().remove(tagName);

            // Feedback
            getSession().info("Removed tag '" + tagName + "'.");

            // AJAX update (including feedback panel)
            target.addComponent(TagSelector.this);
          }
        });
      }
    });
final AutoCompleteTextField<String> inputField = new AutoCompleteTextField<String>("input", new Model<String>(""))
    {
      @Override
      protected Iterator<String> getChoices(String input)
      {
        // For the sake of illustration, return a fixed list here ...
        return DUMMY_TAGS.iterator();
      }
    };
    add(inputField.setOutputMarkupId(true));
    add(new AjaxSubmitLink("add-button")
    {
      @Override
      protected void onSubmit(AjaxRequestTarget target, Form form)
      {
        // Get entered tag name
final String tagName = StringEscapeUtils .unescapeHtml(inputField.getDefaultModelObjectAsString());

        // Verify existence
        final boolean exists = DUMMY_TAGS.contains(tagName);
        if (!exists)
        {
getSession().info("Tag '" + tagName + "' is unknown. Please try again!");
        }

        // Add tag
        else
        {
List<String> currentTags = TagSelector.this.getModelObject(); // is always null!
          if (currentTags.contains(tagName))
          {
getSession().info("Tag '" + tagName + "' already present.");
          }
          else
          {
            currentTags.add(tagName);
            getSession().info("Added tag '" + tagName + "'.");
          }
        }

        // AJAX update (including feedback panel)
        target.addComponent(TagSelector.this);
        target.focusComponent(inputField);
      }
    });
  }

}

---------------------------------------------------------------------
To unsubscribe, e-mail: [EMAIL PROTECTED]
For additional commands, e-mail: [EMAIL PROTECTED]

Reply via email to