Skip to content


Wicket - kombiniertes AutoCompleteBehavoir

Eine der ersten Demonstrationen für die Möglichkeiten von Ajax bestand darin, dass man dem Nutzer während er Eingabe von Informationen Vorschläge unterbreitete, was er denn wohl gemeint haben könnte. Das ist lange her und gehört zum guten Ton einer moderneren Webanwendung. Wicket liefert das notwendige Werkzeug bereits mit, so dass sehr einfach ist, den Nutzer auf diese Art zu unterstützen.

Etwas komplizierter wird es, wenn man dem Nutzer Vorschläge unterbreiten möchte, die nicht nur für ein Eingabefeld relevant sind, sondern wie z.B. bei der Postleitzahl auch den Wert eines anderen Eingabefeldes beeinflussen kann. Im folgenden Beispiel versuchen wir, dem Nutzer bei der Eingabe einer Postleitzahl auch den Ort mit anzuzeigen und den Wert in das Ortsfeld zu übernehmen.

Normalerweise kommen die Daten für die Postleitzahlen aus einer Datenbank, in unserem Beispiel begnügen wir uns mit einer sehr kleinen Auswahl:

package de.wicketpraxis.web.blog.pages.questions.form.autocomplete;

import java.io.Serializable;

public class PlzOrt implements Serializable
{
  String _plz;
  
  String _ort;
  
  public PlzOrt(String plz, String ort)
  {
    _plz=plz;
    _ort=ort;
  }
  
  public String getPlz()
  {
    return _plz;
  }
  
  public String getOrt()
  {
    return _ort;
  }
}
package de.wicketpraxis.web.blog.pages.questions.form.autocomplete;

import java.io.Serializable;
import java.util.ArrayList;
import java.util.List;

public class PlzOrtListFactory implements Serializable
{
  List<PlzOrt> _all=new ArrayList<PlzOrt>();
  
  {
    _all.add(new PlzOrt("23562", "Lübeck"));
    _all.add(new PlzOrt("23858", "Reinfeld"));
    _all.add(new PlzOrt("14199", "Berlin"));
    _all.add(new PlzOrt("70619", "Stuttgart"));
    
  }
  
  public PlzOrtListFactory()
  {
  }
  
  public List<PlzOrt> getList(String plz)
  {
    List<PlzOrt> ret=null;
    if ((plz!=null) && (plz.length()>0))
    {
      ret=new ArrayList<PlzOrt>();
      for (PlzOrt po : _all)
      {
        if (po.getPlz().startsWith(plz)) ret.add(po);
      }
    }
    return ret;
  }
}

Die Methode getList() liefert dann die passende Teilmenge für die eingegebene Postleitzahl. Wenn der Nutzer also "23" eingeben hat, werden die ersten beiden Einträge aus der Liste gewählt.

Wicket hat die Möglichkeit, dem Nutzer Vorschläge unterbreiten zu können, von der Darstellung dieser Vorschläge getrennt. Die relevanten Anpassungen müssen in unserem Fall in der Darstellungskomponente vorgenommen werden. Dazu leiten wir einen eigenen Renderer von einer passenden Wicket-Basisklasse ab:

package de.wicketpraxis.web.blog.pages.questions.form.autocomplete;

import org.apache.wicket.Response;
import org.apache.wicket.extensions.ajax.markup.html.autocomplete.AbstractAutoCompleteRenderer;
import org.apache.wicket.markup.html.form.FormComponent;

public class PlzOrtRenderer extends AbstractAutoCompleteRenderer<PlzOrt>
{
  FormComponent<?> _ortInput;
  
  public PlzOrtRenderer(FormComponent<?> ortInput)
  {
    _ortInput=ortInput;
    _ortInput.setOutputMarkupId(true);
  }
  
  @Override
  protected String getTextValue(PlzOrt object)
  {
    return object.getPlz();
  }

  @Override
  protected void renderChoice(PlzOrt object, Response response, String criteria)
  {
    response.write(object.getPlz() + "-" + object.getOrt());
  }
  
  @Override
  protected CharSequence getOnSelectJavascriptExpression(PlzOrt plzort)
  {
    StringBuilder js = new StringBuilder();
    js.append("wicketGet('").append(_ortInput.getMarkupId()).append("').value ='" + plzort.getOrt() + "';");
    js.append("input");
    return js.toString();
  }

}

In unserer Variante werden folgende Anpassungen vorgenommen: Für das zweite Eingabefeld wird die Ausgabe der MarkupId aktiviert, da wir uns später im Javascript darauf beziehen. Die Methode getTextValue() liefert den Wert zurück, der dann im Eingabefeld für die Postleitzahl erscheint. In der Methode renderChoice() wird die Auswahl gerendert. In unserem Fall zeigen wir Postleitzahl und Ort an. Damit der Ortsname korrekt im anderen Eingabefeld erscheint, übergeben wir durch das Überschreiben der Methode getOnSelectJavascriptExpression() die nötigen Javascript-Aufrufe. Die erste Zeile ermittelt das Objekt und setzt das Atrribut "input" auf den gewünschten Wert. Dabei ist zu beachten, dass die Zeile "input" den Wert darstellt, der in das Postleitzahlfeld geschrieben werden soll. Es sollte an dieser Stelle keine return-Anweisung aufgerufen werden.

package de.wicketpraxis.web.blog.pages.questions.form.autocomplete;

import java.util.Collections;
import java.util.Iterator;
import java.util.List;

import org.apache.wicket.extensions.ajax.markup.html.autocomplete.AutoCompleteBehavior;
import org.apache.wicket.markup.html.form.FormComponent;


class PlzAutoCompleteBehavior extends AutoCompleteBehavior<PlzOrt>
{
  PlzOrtListFactory _listFactory;
  
  public PlzAutoCompleteBehavior(PlzOrtListFactory listFactory, FormComponent<?> ortInput)
  {
    super(new PlzOrtRenderer(ortInput));
    
    _listFactory=listFactory;
  }

  @Override
  protected Iterator<PlzOrt> getChoices(String input)
  {
    List<PlzOrt> list = _listFactory.getList(input);
    if (list!=null) return list.iterator();
    return Collections.EMPTY_LIST.iterator();
  }
}

Wir leiten für dieses Beispiel unsere eigenes Behavior passend ab (Natürlich ist es möglich, das Behavior und den Renderer allgemeingültiger zu gestalten. Darauf wurde aber zu Gunsten der Lesbarkeit verzichtet.) Hinweis: Der Rückgabewert von getChoices() darf in diesem Fall nicht null sein.

Jetzt können wir endlich das Formular bauen und das Behavior einsetzen:

package de.wicketpraxis.web.blog.pages.questions.form.autocomplete;

import org.apache.wicket.extensions.ajax.markup.html.autocomplete.DefaultCssAutocompleteTextField;
import org.apache.wicket.markup.html.CSSPackageResource;
import org.apache.wicket.markup.html.WebPage;
import org.apache.wicket.markup.html.form.Form;
import org.apache.wicket.markup.html.form.TextField;
import org.apache.wicket.model.Model;

public class FormAutoCompletePage extends WebPage
{
  public FormAutoCompletePage()
  {
    add(CSSPackageResource.getHeaderContribution(DefaultCssAutocompleteTextField.class,"DefaultCssAutocompleteTextField.css"));
    
    Form<Void> form = new Form<Void>("form");
    
    TextField<String> plz = new TextField<String>("plz",Model.of(""));
    TextField<String> ort = new TextField<String>("ort",Model.of(""));
    
    plz.add(new PlzAutoCompleteBehavior(new PlzOrtListFactory(),ort));
    
    form.add(plz);
    form.add(ort);
    
    add(form);
  }
}

Für die Darstellung der Auswahl müssten wir jetzt noch etwas CSS bemühen. Das ersparen wir uns in diesem Beispiel, in dem wir die CSS-Datei der DefaultCssAutocompleteTextField-Klasse einbinden.

Eine kleine Besonderheit ist zu beachten: Man muss die Vorschläge, die der Browser dem Nutzer macht, unterbinden, damit die beiden Auswahlmöglichkeiten nicht kollidieren. Dazu fügt man im Markup das Attribut "autocomplete" mit dem Wert "off" hinzu.

<html>
  <head>
    <title>FormAutoCompletePage</title>
  </head>
  <body>
    <form wicket:id="form">
      Postleitzahl: <input wicket:id="plz" autocomplete="off" ></input><br>
      Ort: <input wicket:id="ort" autocomplete="off" ></input><br>
      <input type="submit" value="Button"> 
    </form>
  </body>
</html>

Und so sieht es dann aus:

wicket-combined-autocomplete-behavoir

Tags:

Veröffentlicht in Wicket, .

Wicket Form Submit - mit und ohne Ajax

Webanwendungen ohne Formulare gibt es nicht. Dabei ist die korrekte Formularbehandlung alles andere als trivial. Zum Glück bietet Wicket eine ausgezeichnete Unterstützung für Formulare, die kaum Wünsche offen lässt. Doch auch mit Wicket sind ein paar Dinge zu beachten, um die verschiedenen Interaktionsmöglichkeiten des Nutzers korrekt zu verarbeiten.

Wicket bietet die Möglichkeit, neben dem normalen Abschicken eines Formulars auch auf die angeklickten Submit-Buttons reagieren zu können. Damit man aber auch zuverlässig unterscheiden kann, ob der Nutzer das Formular durch ein Enter im Textfeld oder durch einen Klick auf einen Button abgeschickt hat, muss man ein paar Vorbereitungen treffen.

Für das Formular legen wir eine Bean an, welche die Daten aufnimmt.

package de.wicketpraxis.web.blog.pages.questions.form.submit;

import java.io.Serializable;

public class FormBean implements Serializable
{
  String _name;
  
  public String getName()
  {
    return _name;
  }
  
  public void setName(String name)
  {
    _name = name;
  }
}

Für unser Beispiel benötigen wir ein Formular, einen AjaxFallbackButton, einen normalen Button und einen Button, den wir dazu benutzen, denn Fall herauszubekommen, wenn der Nutzer einfach nur Enter gedrückt hat. Das FeedbackPanel sollte man auch nicht vergessen.

package de.wicketpraxis.web.blog.pages.questions.form.submit;

import org.apache.wicket.ajax.AjaxRequestTarget;
import org.apache.wicket.ajax.markup.html.form.AjaxFallbackButton;
import org.apache.wicket.markup.html.WebPage;
import org.apache.wicket.markup.html.form.Button;
import org.apache.wicket.markup.html.form.Form;
import org.apache.wicket.markup.html.form.TextField;
import org.apache.wicket.markup.html.panel.FeedbackPanel;
import org.apache.wicket.model.CompoundPropertyModel;

public class FormSubmitPage extends WebPage
{
  int _counter;
  
  public FormSubmitPage()
  {
    final FeedbackPanel feedbackPanel = new FeedbackPanel("feedback");
    feedbackPanel.setOutputMarkupId(true);
    add(feedbackPanel);
    
    CompoundPropertyModel<FormBean> formModel = new CompoundPropertyModel<FormBean>(new FormBean());
    Form<FormBean> form = new Form<FormBean>("form",formModel)
    {
      @Override
      protected void onSubmit()
      {
        info("Form Submit: "+_counter++);
      }
    };
    
    form.add(new TextField<String>("name"));
    
    form.add(new Button("defaultSubmit")
    {
      @Override
      public void onSubmit()
      {
        info("Default Button: "+_counter++);
      }
    });
    
    form.add(new Button("submit")
    {
      @Override
      public void onSubmit()
      {
        info("Button: "+_counter++);
      }
    });
    
    form.add(new AjaxFallbackButton("ajaxSubmit",form)
    {
      @Override
      protected void onSubmit(AjaxRequestTarget target, Form<?> form)
      {
        if (target!=null)
        {
          info("AjaxSubmit Button(ajax): "+_counter++);
          target.addComponent(feedbackPanel);
        
          _counter=0;
        }
        else
        {
          info("AjaxFallbackButton: "+_counter++);
        }
      }
    });
    
    add(form);
  }
  
  @Override
  protected void onBeforeRender()
  {
    _counter=0;
    super.onBeforeRender();
  }
}

Damit man die Reihenfolge besser erkennen kann, mit der die onSubmit-Methoden aufgerufen werden, wird ein Zähler (_counter) hochgezählt und vor dem Darstellen des Formulars wieder zurückgesetzt. In diesem Beispiel liegt die entscheidende Information im Markup. Dabei ist die Reihenfolge der verschiedenen Submit-Komponenten wichtig.

<html>
  <head>
    <title>FormSubmitPage</title>
  </head>
  <body>
    <div wicket:id="feedback"></div>
    
    <form wicket:id="form">
      <input wicket:id="defaultSubmit" type="submit" value="" style="border:0px; width: 0px; height: 0px; visibility: collapse; display: compact;">
      Name <input wicket:id="name"><br>
      <input wicket:id="ajaxSubmit"  type="submit" value="AjaxButton">
      <input wicket:id="submit" type="submit" value="Button"> 
    </form>
  </body>
</html>

Der Button mit der Wicket-ID defaultSubmit muss vor allen anderen Submit-Komponenten stehen. Dadurch wird beim Abschicken des Formulars durch Enter dieser Button ausgewählt. Wenn einer der anderen Buttons angeklickt wird, dann wird das Formular über diesen Button abgeschickt. Doch warum soviel Aufwand? Die onSubmit()-Methode des Formulars wird doch in jedem Fall aufgerufen.

Der Aufwand ist notwendig, wenn man abhängig davon, ob der Nutzer auf einen Button oder eben auf keinen Button geklickt hat, eine Aktion ausführen möchte. Das bedeutet, dass man die Aktion nicht in onSubmit ausführen kann. Es ist allerdings auch nicht möglich, im onSubmit() der Buttonkomponenten ein Flag zu setzen, dass dann in der onSubmit()-Methode des Formulars aufgerufen wird, da die Methode beim AjaxFallbackButton erst nach dem onSubmit() der Komponente aufgerufen wird.

Folgende Ergebnisse erhält man, wenn man das Formular a) per Enter, b) per AjaxButton und c) per Button abschickt:

Submit per Enter

Submit per AjaxButton

Submit per Button

Wenn Javascript deaktiviert ist, dann erhält man folgende Ausgabe: Submit per Enter

Submit per AjaxButton

Submit per Button

Wenn man dieses Vorgehen beherzigt, funktioniert die Anwendung auch mit deaktiviertem JavaScript genauso zuverlässig. Das freut den Nutzer und in diesem Fall auch den Entwickler:)

Tags:

Veröffentlicht in Technologie, Wicket, .

Migration zu Wicket : Formulare

Formulare sind wesentlicher Bestandteil einer Webanwendung. Doch gerade beim Umstieg von einem anderen Framework kommt es in diesem Bereich zu Irritationen. Warum? Ein wesentlicher Unterschied besteht darin, dass es in Wicket nicht zwingend eine Ergebnisseite geben muss. Ich möchte das an einem Beispiel veranschaulichen.

Als erstes erstellen wir eine JavaBean in der das Formular die Daten ablegt:

package de.wicketpraxis.web.blog.pages.questions.migration.forms;

import java.io.Serializable;

public class FormBean implements Serializable
{
  String _name;
  
  public String getName()
  {
    return _name;
  }
  
  public void setName(String name)
  {
    _name = name;
  }
}

Nichts besonderes. Die Bean hat das Attribut "Name". Erstellen wir eine Seite, die über ein Formular diese Bean mit Werten füllt:

package de.wicketpraxis.web.blog.pages.questions.migration.forms;

import java.io.Serializable;

import org.apache.wicket.markup.html.WebPage;
import org.apache.wicket.markup.html.form.Form;
import org.apache.wicket.markup.html.form.TextField;
import org.apache.wicket.model.CompoundPropertyModel;

public class MinimalFormPage extends WebPage
{
  public MinimalFormPage()
  {
    Form<FormBean> form = new Form<FormBean>("form",new CompoundPropertyModel<FormBean>(new FormBean()));
    
    form.add(new TextField<String>("Name"));
    
    add(form);
  }
}

Wie wir sehen, wird ein Formular eingebunden und in dieses Formular ein Textfeld für das Attribut benutzt. Damit ist dieses Beispiel funktionsfähig. Es macht nur nicht besonders viel. Was aber gut zu erkennen ist:

  • es wird keine Ergebnisseite benötigt
  • es muss keine Methode überschrieben werden, um die Eingabedaten in der Bean abzulegen

Das Markup ist ebenfalls recht einfach:

<html>
  <head>
    <title>MinimalFormPage</title>
  </head>
  <body>
    <form wicket:id="form">
      Name <input wicket:id="Name"><br>
      <input type="submit" value="Absenden">
    </form>
  </body>
</html>

Interessant: der Submit-Button hat in diesem Beispiel keine Entsprechung als Wicket-Komponente. Das Formular wird trotzdem abgeschickt.

Komplexes Beispiel

Kommen wir nun zu einem etwas komplexeren Beispiel, dass eine Ergebnisseite verwendet. Dabei an dieser Stelle nocheinmal der Hinweis: die Ergebnisseite wird verwendet, weil wir das in diesem Beispiel so wollten. Alles was auf der Ergebnisseite dargestellt werden kann, könnte man auch ganz einfach auf der Seite darstellen, auf der auch das Formular eingebunden ist.

Als erstes erstellen wir die Ergebnisseite:

package de.wicketpraxis.web.blog.pages.questions.migration.forms;

import org.apache.wicket.PageParameters;
import org.apache.wicket.markup.html.WebPage;
import org.apache.wicket.markup.html.basic.Label;

public class ResultPage extends WebPage
{
  public ResultPage(String name)
  {
    init(name);
  }
  
  public ResultPage(PageParameters pageParameters)
  {
    init(pageParameters.getString("Name"));
  }
  
  protected void init(String name)
  {
    add(new Label("name",name));
  }
}
<html>
  <head>
    <title>ResultPage</title>
  </head>
  <body>
    Name <span wicket:id="name"></span>
  </body>
</html>

Die Seite besitzt zwei Konstruktoren. Der erste erwartet einen String als Parameter, der zweite wertet die Seitenparameter aus (wenn die Seite z.B. mit ?Name=klaus aufgerufen wird). Der Wert wird durch das Label zur Anzeige gebracht.

Jetzt die Formularseite:

package de.wicketpraxis.web.blog.pages.questions.migration.forms;

import java.io.Serializable;
import java.util.HashMap;
import java.util.Map;

import org.apache.wicket.PageParameters;
import org.apache.wicket.markup.html.WebPage;
import org.apache.wicket.markup.html.form.Form;
import org.apache.wicket.markup.html.form.TextField;
import org.apache.wicket.markup.html.panel.FeedbackPanel;
import org.apache.wicket.model.CompoundPropertyModel;

public class KomplexFormPage extends WebPage
{
  public KomplexFormPage()
  {
    add(new FeedbackPanel("feedback"));
    
    Form<FormBean> form = new Form<FormBean>("form",new CompoundPropertyModel<FormBean>(new FormBean()))
    {
      @Override
      protected void onSubmit()
      {
        // Variante 1
        setResponsePage(new ResultPage(getModelObject().getName()));
        
        // Variante 2
        Map<String,String> map=new HashMap<String, String>();
        map.put("Name", getModelObject().getName());
        setResponsePage(ResultPage.class, new PageParameters(map));
        
        // Variante ?
      }
    };
    
    form.add(new TextField<String>("Name").setRequired(true));
    
    add(form);
  }
}

Wir haben in diesem Beispiel ein FeedbackPanel hinzugefügt, da wir auch das Textfeld zum Pflichtfeld gemacht haben. Ohne FeedbackPanel kommt sonst der Hinweis, dass man etwas eingeben muss, nicht zur Anzeige. Ansonsten haben wir die onSubmit-Methode überschrieben, die die Ergebnisseite aufruft. Dabei können wir zum einen eine Instanz der Seite erstellen, in dem wir (vorrausgesetzt es gibt einen passenden Konstruktor) den/die gewünschten Parameter direkt übergeben. Das wir in diesem Beispiel nur ein String übergeben, soll nicht darüber hinwegtäuschen, dass jedes beliebige (also auch weit komplexere) Objekte übergeben werden können.

Die zweite Variante verpackt den Parameter in einen Seitenparameter und springt die Seite dann über eine passende Url an. In diesem Fall werden natürlich die übergebenen Parameter für den Nutzer sichtbar. Das entspricht auch eher dem klassischen Verständnis einer Formularbehandlung in anderen Frameworks. Der Unterschied besteht allerdings schon darin, dass an dieser Stelle die Formularbehandlung bereits abgeschlossen ist und wir nur noch einmal absichtlich auf eine andere Seite springen.

Daher ist die letzte Variante auch nur mit einem Fragezeichen versehen. Wenn nichts dafür spricht, dass man eine wie auch immer geartete Ergebnisseite benötigt, kann man diese auch weglassen. Man sollte vielmehr darauf zurückgreifen, dass man Komponenten ein und ausblendet, wenn man das Formular nach erfolgreichem Ausfüllen nicht mehr anzeigen möchte.

Zusammenfassung

Ich hoffe, ich konnte zeigen, dass man sich vom dem klassischen Konzept einer Formularseite trennen muss und die Formularverarbeitung in Wicket ihre Entsprechung vermutlich eher in Swing findet.

Tags:

Veröffentlicht in Migration, Wicket, .

Datenbankeinträge auswählen mit der CheckGroup

Ich wurde gefragt, ob in meinem Buch (Praxisbuch Wicket) die Verwendung der CheckGroup-Komponente erläutert wird. Die Anwort ist einfach: ja.

Was in dem Beispiel aber nicht gezeigt wird, ist das dynamische Erzeugen der Auswahlliste durch Daten aus einer Datenbank. Der Absender hat sich aber genau für diesen Fall interessiert, so dass ich an dieser Stelle mal ein einfaches Beispiel geben möchte, wie man soetwas realisieren kann.

Das Beispiel

package de.wicketpraxis.web.blog.pages.questions.checkgroup.fromdb;

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

import org.apache.wicket.markup.html.WebPage;
import org.apache.wicket.markup.html.basic.Label;
import org.apache.wicket.markup.html.form.Check;
import org.apache.wicket.markup.html.form.CheckGroup;
import org.apache.wicket.markup.html.form.Form;
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.LoadableDetachableModel;
import org.apache.wicket.model.Model;
import org.apache.wicket.model.util.CollectionModel;
import org.apache.wicket.spring.injection.annot.SpringBean;

import de.wicketpraxis.persistence.beans.User;
import de.wicketpraxis.persistence.dao.UserDao;

public class CheckGroupFromDbPage extends WebPage
{
  @SpringBean
  UserDao _userDao;
  
  public CheckGroupFromDbPage()
  {
    LoadableDetachableModel<List<User>> userListModel=new LoadableDetachableModel<List<User>>()
    {
      @Override
      protected List<User> load()
      {
        return _userDao.findAll(0, 10);
      }
    };
    
    final IModel<Collection<Integer>> selectedModel = new CollectionModel<Integer>(new ArrayList<Integer>());
    
    add(new FeedbackPanel("feedback"));
    
    Form<Void> form=new Form<Void>("form")
    {
      @Override
      protected void onSubmit()
      {
        info("Elemente selectiert: "+selectedModel.getObject());
      }
    };
    
    CheckGroup<Integer> checkGroup=new CheckGroup<Integer>("checkGroup",selectedModel);
    form.add(checkGroup);
    
    checkGroup.add(new ListView<User>("list",userListModel)
    {
      @Override
      protected void populateItem(ListItem<User> item)
      {
        item.add(new Check<Integer>("check",Model.of(item.getModelObject().getId())));
        item.add(new Label("name",item.getModelObject().getName()));
      }
    });
    
    add(form);
    
  }
}

Und das Markup-File:

<html>
  <head>
    <title>CheckGroup from DB</title>
  </head>
  <body>
    <div wicket:id="feedback"></div>
    
    <form wicket:id="form">
      <wicket:container wicket:id="checkGroup">
      <wicket:container wicket:id="list">
        <input wicket:id="check" type="checkbox"> <span wicket:id="name"></span><br>
      </wicket:container>
      </wicket:container>
      <input type="submit" value="Auswählen">
    </form>
  </body>
</html>

Die Variable _userDao beinhaltet die Datenbankzugriffsklasse. Da wir die Variable als Field definiert haben, können wir ohne weiteres innerhalb der Klasse darauf zugreifen. Wicket sorgt für alle über die SpringBean-Annotation initialisierten Felder dafür, dass es mit der Serialisierung der Komponente keine Probleme gibt.

Als nächstes erstellen wir ein Modell, dass die gewünschte Auswahlmenge ermittelt. An dieser Stelle könnte man über ein CascadingLoadableDetachableModel (kein Wicket-Standard, siehe Buch Seite 65 oder hier im Blog) auch auf die Modelldaten eines Eingabefeldes zurückgreifen um die Abfrage einsprechende zu beeinflussen zu können. Das Ergebis ist eine Liste von Objekten.

Als zweiter erstellen wir ein Modell, in dem die IDs der ausgewählten Elemente landen. Um den Aufwand einer eigenen Implementierung einer Modellklasse für eine Collection von persistenten Objekten zu sparen, legen wir nur die ID des Elements, nicht das Element selbst in der Auswahlliste ab.

Das Feedbackpanel dient zur Anzeige die Message, die in der onSubmit-Methode des Formulars ausgegeben wird. Das Formular hat in diesem Fall kein eigenes Modell (nur der Einfachheit halber wird in dem Beispiel auf die Verwendung eines CompoundPropertyModel verzichtet).

Jetzt kommt der spannende Teil. Der CheckGroup-Komponente wird als Parameter das Modell übergeben, in der die Ausgewählten Elemente gesammelt werden sollen. Dann wird in der ListView für alle zur Verfügung stehenden Elemente eine Check-Komponente hinzugefügt, die als Modell nicht das Objekt, sondern die ID des Datenbankeintrags übergeben bekommt.

Funktionsweise

Wenn das Formular abgeschickt wird, ermittelt Wicket alle Check-Komponenten, die aktiviert waren. Für diese Komponenten wird der Inhalt des Modells ermittelt und der Auswahlliste hinzugefügt. Abschließend wird das Modell, dass die Auswahlliste beinhaltet entsprechend gesetzt. Dabei können beliebige Typen für die Auswahlliste benutzt werden, solange sie serialisierbar sind. Kommen die Daten aus einer Datenbank empfiehlt sich der Einsatz eines Primärschlüssels, anhand dessen das Objekt ermittelbar bleibt.

Tags:

Veröffentlicht in Allgemein, Wicket, .