Skip to content


Migration zu Wicket: Ajax

Einer der Aspekte, die bei meiner Entscheidung für ein neues Webframework eine große Rolle spielten, war die Integration von Ajax. Fast jedes aktuelle Framework bietet eine Unterstützung von Ajax, doch unterscheiden sie sich in Handhabung und Möglichkeit.

Die komponentenorientierte Arbeitsweise von Wicket führt dazu, dass eine Wicket-Seite (die Entsprechung einer Webseite), aus einem Komponentenbaum besteht, bei der jede Komponente für ihre Darstellung verantwortlich ist. Daher ist es besonders einfach, den Teil zu identifizieren, der durch die jeweilige Komponente dargestellt wird. Diesen Umstand macht sich Wicket zu nutze, um im Gegensatz zu anderen Frameworks, beliebig viele Bereiche der Webseite aktualisieren zu können.

Im folgenden Beispiel soll das veranschaulicht werden:

package de.wicketpraxis.web.blog.pages.migration.ajax;

import org.apache.wicket.ajax.AjaxRequestTarget;
import org.apache.wicket.ajax.markup.html.AjaxFallbackLink;
import org.apache.wicket.markup.html.WebMarkupContainer;
import org.apache.wicket.markup.html.WebPage;
import org.apache.wicket.markup.html.basic.Label;
import org.apache.wicket.markup.html.panel.FeedbackPanel;
import org.apache.wicket.model.Model;

public class AjaxMultiUpdatePage extends WebPage
{
  public AjaxMultiUpdatePage()
  {
    final FeedbackPanel feedback=new FeedbackPanel("feedback");
    feedback.setOutputMarkupId(true);
    add(feedback);
    
    // die geschweiften Klammern haben keine Funktion
    // sie sollen nur den Komponentenbaum veranschaulichen
    WebMarkupContainer block = getBlock(feedback,1);
    {
      WebMarkupContainer block2 = getBlock(feedback,2);
      {
        WebMarkupContainer block3 = getBlock(feedback,3);
        block2.add(block3);
      }
      block.add(block2);
    }
    add(block);
  }

  private WebMarkupContainer getBlock(final FeedbackPanel feedback, int start)
  {
    final WebMarkupContainer block = new WebMarkupContainer("ajaxUpdate");
    block.setOutputMarkupId(true);
    
    Model<Integer> model = Model.of(start);
    final Label label = new Label("count",model);
    label.setOutputMarkupId(true);
    block.add(label);
    
    block.add(new AjaxFallbackLink<Integer>("link",model)
    {
      @Override
      public void onClick(AjaxRequestTarget target)
      {
        setModelObject(getModelObject()+1);
        info("Aktualisiere "+getPath());
        if (target!=null)
        {
          target.addComponent(feedback);
          target.addComponent(block);
          
          // ist nicht nötig
          target.addComponent(label);
        }
      }
    });
    
    return block;
  }
}

Wir fügen der Seite ein FeedbackPanel hinzu. Für jede Komponente, die per Ajax aktualisiert werden soll, muss die setOutputMarkupId(true) aufgerufen werden. Dass veranlasst Wicket, in dem Html-Tag dieser Komponente das id-Attribut zu setzen. Das ist notwendig, damit Wicket diesen Tag dann durch neuen Inhalt ersetzen kann.

Als weiteres erzeugen wir einen WebMarkupContainer. Dieses Element dient uns als Rahmen, um die Aktualisierung des ganzen Blocks anstoßen zu können. Als Kindelemente definieren wir zusätzlich ein Label, das den Inhalt eines Modells darstellt, dass wir gleichzeitig in einem AjaxFallbackLink benutzen. Klickt der Nutzer auf den Link, wird der Wert im Modell erhöht und der Block sowie das FeedbackPanel in die Liste der zu aktualisierenden Komponenten aufgenommen. Auch das Label wurde zu dieser Liste hinzugefügt. Allerdings kommt hier bereits eine Optimierung zum Vorschein, die Wicket vornehmen kann, da der Komponentenbaum bekannt ist: Wicket ersetzt den ganzen Block und weiß, dass damit auch das Label aktualisiert wurde, weshalb es nicht gesondert ersetzt werden muss.

Innerhalb eines Blockes fügen wir einen weiteren als Kindelement ein. Das wiederholen wir noch einmal. Wird in dieser Konstellation nun der äußere Block aktualisiert, werden auch alle Kindelemente aktualisiert. Dieses Verhalten kann man überprüfen, in dem man die Kommunikation im WicketAjaxDebug-Fenster betrachtet.

Wicket Ajax Debug Window

Deaktiviert man JavaScript und damit Ajax, dann funktioniert die Seite trotzdem, da dann die ganze Seite neu gerendert wird. Auf diese Weise kann man Webanwendungen mit Ajax-Unterstützung entwickeln, ohne dass man Nutzer, die aus welchen Gründen auch immer JavaScript deaktiviert haben, im Regen stehen lässt.

<html>
  <head>
    <title>AjaxMultiUpdate</title>
    <style type="text/css">
      .block
      {
        border:1px solid dashed;
      }
    </style>
  </head>
  <body>
    <h1>Ajax Test</h1>
    <div wicket:id="feedback"></div>
    
    <div wicket:id="ajaxUpdate" class="block">
      <span wicket:id="count">123</span> <a wicket:id="link">+1</a>
      <div wicket:id="ajaxUpdate" class="block">
        <span wicket:id="count">123</span> <a wicket:id="link">+1</a>
        <div wicket:id="ajaxUpdate" class="block">
          <span wicket:id="count">123</span> <a wicket:id="link">+1</a>
          
        </div>
      </div>
    </div>
  </body>
</html>

Dieses Beispiel offenbart wesentliche Unterschiede zwischen der Ajax-Integration von Wicket und anderen Frameworks:

  • Wicket kann beliebig viele Komponenten innerhalb eines Request aktualisieren.
  • Wicket kann die Aktualisierung optimieren.
  • Auch bei deaktiviertem Javascript ist die Funktion der Anwendung gewährleistet.

Tags:

Veröffentlicht in Migration, Wicket, .