Dans ce 5ème article de notre série “Amusons nous avec Wicket & Ajax : Onglets dynamiques”, nous allons tenter de mettre un peu d’ordre dans le code qu’on à écrit dans les étapes précédentes.

Premièrement nous allons nous occuper du “stockage” des informations pertinentes, puis nous allons rendre nos onglets autonomes (pour pourquoi pas les utiliser dans un autre projet).

ce que l'on veut

OngletsModelObject

Nous allons d’abord commencer par organiser les données utiles pour nos onglets :
Il nous faut :

  • La liste des libellés des onglets
  • La liste des panneaux à afficher en fonction de l’onglet choisi
public class OngletsModelObject implements Serializable {
  private Integer indexOngletActif = 0;
 
  private List<String> listOnglets;
 
  private List<MarkupContainer> listContentPanels;
 
  public OngletsModelObject(List<String> _listOnglets, List<MarkupContainer> _listContentPanels) {
	this.listOnglets = _listOnglets;
	this.listContentPanels = _listContentPanels;
  }
  ...
  // Getter / Setter
}

Et nous allons utiliser cet objet (que nous mettons dans un Model) pour stocker nos infos d’onglets :

  List<String> listOnglets = Arrays.asList(new String[] { "Salarié", 
	"Contrat", "Planning" });
  List<MarkupContainer> listContentPanels = Arrays.asList(new 
	MarkupContainer[] {new PanelGenerique("content", "panel 5 Salarié"), 
	new PanelGenerique("content", "panel 5 Contrat"), new PanelGenerique("content", "panel 5 Planning") });
 
  CompoundPropertyModel<OngletsModelObject> ongletsModel = new 
	CompoundPropertyModel<OngletsModelObject>(new OngletsModelObject(listOnglets, listContentPanels));

PanelOnglets

De plus nous allons déporter le Panel des onglets dans une classe à part :

public class PanelOnglets extends Panel {
  private WebMarkupContainer ongletsContainer;
  private CompoundPropertyModel<OngletsModelObject> ongletsModel;
 
  public PanelOnglets(String _id, CompoundPropertyModel<OngletsModelObject> _ongletsModel) {
  super(_id);
 
  // CSS
  add(CSSPackageResource.getHeaderContribution(this.getClass(), this.getClass()
	.getSimpleName() + ".css"));
 
  this.ongletsModel = _ongletsModel;
 
  // Repeater des onglets
  ListView<String> onglets = new ListView<String>("onglet", ongletsModel.getObject()
	.getListOnglets()) {
	@Override
	protected void populateItem(final ListItem<String> _item) {
	String libelle = _item.getModelObject();
	AjaxLink<Object> linkOnglet = new AjaxLink<Object>("linkOnglet") {
 
	  @Override
	  public void onClick(AjaxRequestTarget target) {
	  ...
	  }
	};
	Label labelOnglet = new Label("labelOnglet", libelle);
	linkOnglet.add(labelOnglet);
	_item.add(linkOnglet);
	}
 
	@Override
	protected ListItem<String> newItem(int _index) {
	final int ongletNumber = _index;
	return new ListItem<String>(_index, getListItemModel(getModel(), _index)) {
	  @Override
	  protected void onBeforeRender() {
	  super.onBeforeRender();
 
	  int ongletActif = ongletsModel.getObject().getIndexOngletActif();
	  int ongletLast = ongletsModel.getObject().getListOnglets().size() - 1;
 
	  add(new AttributeModifier("class", true, new OngletClassAttributeModel(
		ongletActif, ongletNumber, ongletLast)));
	  }
	};
	}
  };
 
  // Container des Onglets
  ongletsContainer = new WebMarkupContainer("ongletsContainer");
  ongletsContainer.setOutputMarkupId(true);
  ongletsContainer.add(onglets);
  add(ongletsContainer);
  }
}

On y retrouve tous les constituants des onglets :

  • Le WebMarkupContainer ongletsContainer
  • Le CompoundPropertyModel ongletsModel
  • Le ListView onglets
  • La méthode newItem(int _index)

PageEtape5

La page, elle est juste plus claire avec la déclaration de notre PanelOnglets :

public class PageEtape5 extends TemplatePage {
  private PanelOnglets ongletsPanel;
  private WebMarkupContainer contentContainer;
  private CompoundPropertyModel<OngletsModelObject> ongletsModel = null;
 
  public PageEtape5() {
  super();
  initPageTitle("Etape 5");
 
  List<String> listOnglets = Arrays.asList(new String[] { "Salarié", 
	"Contrat", "Planning" });
  List<MarkupContainer> listContentPanels = Arrays.asList(new 
	MarkupContainer[] {new PanelGenerique("content", "panel 5 
	Salarié"), new PanelGenerique("content", "panel 5 Contrat")
	, new PanelGenerique("content", "panel 5 Planning") });
 
  ongletsModel = new CompoundPropertyModel<OngletsModelObject>(new 
	OngletsModelObject(listOnglets, listContentPanels));
 
  // Container des Onglets
  ongletsPanel = new PanelOnglets("ongletsPanel", ongletsModel);
  ongletsPanel.setOutputMarkupId(true);
  add(ongletsPanel);
 
  // Container du contenu
  contentContainer = new WebMarkupContainer("contentContainer");
  contentContainer.setOutputMarkupId(true);
  contentContainer.add(getOngletsModel().getObject().getPanelContent(
	getOngletsModel().getObject().getIndexOngletActif()));
  add(contentContainer);
  }
 
  public CompoundPropertyModel<OngletsModelObject> getOngletsModel() {
  return ongletsModel;
  }
}

Tous les constituants de la page sont là :

  • Le PanelOnglets ongletsPanel
  • Le WebMarkupContainer contentContainer
  • Le CompoundPropertyModel ongletsModel

Un Problème ?

Oui un problème : est ce que cela doit être l’onglet qui sait ce qui doit être fait lorsque l’on clique dessus, ou alors est ce qu’il faut mettre en place un système pour déléguer la gestion du clic ?

Si jamais c’est l’onglet qui s’occupe de tout, il faut savoir qu’il faudra passer en paramètre ou autre les différents composants que l’on cherche à mettre à jour.

J’ai décidé de faire quelque chose de plus pratique.

IOngletObserver

On va reprendre le principe de l’Observer/Observable. En premier lieu, l’interface au centre de ce principe :

public interface IOngletObserver {
  public void onOngletClick(AjaxRequestTarget target, Integer index);
}

Ensuite il faut mettre en place, dans le PanelOnglets, le moyen de notifier ceux qui l’écouteront (observer) que le clique à été effectué :

public class PanelOnglets extends Panel {
  private IOngletObserver observer = null;
  public PanelOnglets(String _id, CompoundPropertyModel<OngletsModelObject> _ongletsModel) {
	...
	// Repeater des onglets
	ListView<String> onglets = new ListView<String>("onglet", ongletsModel.getObject().getListOnglets()) {
	  @Override
	  protected void populateItem(final ListItem<String> _item) {
		String libelle = _item.getModelObject();
		AjaxLink<Object> linkOnglet = new AjaxLink<Object>("linkOnglet") {
		  @Override
		  public void onClick(AjaxRequestTarget target) {
			// Delegation de l'action a l'Observer
			if (observer != null) {
			  observer.onOngletClick(target, _item.getIndex());
			}
		  }
		};
		...
	  }
	  ...
	};
  }
  public PanelOnglets setObserver(IOngletObserver observer) {
	this.observer = observer;
	return this;
  }
}

Enfin il nous faut modifier la PageEtape5 pour qu’elle implémente cette Interface (la méthode onOngletClick), ainsi que de s’abonner auprès du PanelOnglets :

public class PageEtape5 extends TemplatePage implements IOngletObserver {
  ...
  public PageEtape5() {
	super();
	...
	// Container des Onglets
	ongletsPanel = new PanelOnglets("ongletsPanel", ongletsModel).setObserver(this);
	ongletsPanel.setOutputMarkupId(true);
	add(ongletsPanel);
	...
  }
  public void onOngletClick(AjaxRequestTarget _target, Integer _index) {
	// Menu
	getOngletsModel().getObject().setIndexOngletActif(_index);
	_target.addComponent(ongletsPanel);
 
	// Content
	WebMarkupContainer newContentContainer = new WebMarkupContainer("contentContainer");
	newContentContainer.setOutputMarkupId(true);
	newContentContainer.add(getOngletsModel().getObject().getPanelContent(getOngletsModel().getObject().getIndexOngletActif())); 
	contentContainer.replaceWith(newContentContainer);
	contentContainer = newContentContainer;
	_target.addComponent(newContentContainer);
  }
}

“Et voilà” comme disent les ricains!

Tout est bien rangé, assez propre, on pourrait presque en faire un composant réutilisable.

J’ai mis en ligne le résultat étape par étape, et voilà le code source (sous la forme d’un projet Eclipse, il vous faudra aussi maven pour la gestion des dépendances)

PS : Greg m’a très justement fait remarqué qu’un “busy indicator” ne serait pas inutile pour que l’utilisateur soit au courant qu’il se passe quelque chose si d’aventure le temps de chargement était trop long.
Il y aura donc une 6ème étape très prochainement !

Imprimer cet article Imprimer cet article

  3 Responses to “Amusons nous avec Wicket & Ajax : Onglets dynamiques 5/5”

  1. Bah moi j’aurais toujours la même remarque:

    Quitte à utiliser Ajax, il serait mieux d’activer le nouvel onglet au moment du clic et non au retour de la requête, quitte à y mettre l’indicateur de chargement. Parce que là du coup on se retrouve avec un temps de latence et l’utilisation d’Ajax n’apporte pas de différence avec un chargement classique. :p

    Autre remarque (d’un point de vue purement pratique) : je ne sais pas à quoi sont destinés ces onglets mais pouvoir spécifier un “#planning” par exemple à la fin de l’URL pour se retrouver directement sur l’onglet “Planning” pourrait être intéressant, et éviterait le syndrôme “site en Flash” qui impose de toujours passer par la page d’accueil pour pouvoir cheminer jusqu’à la page souhaitée.

    Mais sinon c’est vraiment bien de remettre des nouveaux exemples de code, je testerai ça dès qu’Eclipse ne sera plus fâché avec moi.

  2. Concernant ta première remarque, je suis assez d’accord. Je vais voir pour faire une 2ème version de cette facon.

    Pour la deuxième je suis complètement d’accord. Mais la, je t’avoue que c’est un manque de connaissance qui me bloque. Je vais continuer d’investiguer.

    Courage, Eclipse ne t’en veux pas vraiment en fait…

  3. [...] à la première remarque de Grégo dans son commentaire, j’ai modifié quelque peu l’étape 5 pour tenter d’avoir le fonctionnement [...]

 Leave a Reply

(required)

(required)


9 × = eighteen

You may use these HTML tags and attributes: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <strike> <strong> <pre lang="" line="" escaped="" highlight="">

   
© 2011 NooCodeCommit Suffusion theme by Sayontan Sinha