Voici le premier article dédié à l’utilisation de JQuery4Wicket.
Une première approche qui vous montre comment utiliser simplement JQuery dans vos applications Wicket.
Cet article nécessite quelques connaissances de base en Wicket et JQuery. NooCodeCommit.com ne pourra être tenu responsable d’éventuelles séquelles rétiniennes permanentes ou temporaires dues à la lecture des lignes qui suivent
.
Préparation
Je vais passer ici la partie qui consiste à créer une application web avec Wicket.
Si vous avez besoin d’une piqure de rappel, je vous invite à consulter ce post de nicogiard.
La première chose à faire pour utiliser JQuery4Wicket est de copier le .jar de la dernière version dans votre répertoire WEB-INF/lib
Premiers pas
Lorsque vous utilisez JQuery dans des pages HTML classiques, vous devez insérer dans la section head de votre page les fichiers .js correspondants.
|
1 2 |
<script type="text/javascript" src="jquery-1.2.6.js"></script> <script type="text/javascript" src="ui/ui.core.js"></script> |
Pour pouvoir utiliser JQuery dans vos pages, il faut donc demander à Wicket d’insérer les fichiers souhaités.
Pour cela, vous allez ajouter dans le constructeur de votre page la ligne suivante
|
1 |
JQCore.init(this); |
Ce qui nous donne tout simplement
|
1 2 3 4 5 6 7 8 9 10 11 |
import org.apache.wicket.markup.html.WebPage; import com.noocodecommit.wicket.stuff.jquery.JQCore; public class TutorialPage extends WebPage { public TutorialPage() { super(); JQCore.init(this); } } |
Si vous éxécutez la page dans votre navigateur web préféré et que vous affichez la source,
vous pourrez voir dans la section head les lignes suivantes
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 |
<script type="text/javascript" src="resources/com.noocodecommit.wicket.stuff.jquery.JQCore/lib/jquery.js"></script> <script type="text/javascript" src="resources/com.noocodecommit.wicket.stuff.jquery.plugin.effects.JQAnimation/lib/effects.core.js"></script> <script type="text/javascript" src="resources/com.noocodecommit.wicket.stuff.jquery.plugin.effects.blind.JQBlindPlugin/lib/effects.blind.js"></script> <script type="text/javascript" src="resources/com.noocodecommit.wicket.stuff.jquery.plugin.effects.bounce.JQBouncePlugin/lib/effects.bounce.js"></script> <script type="text/javascript" src="resources/com.noocodecommit.wicket.stuff.jquery.plugin.effects.clip.JQClipPlugin/lib/effects.clip.js"></script> <script type="text/javascript" src="resources/com.noocodecommit.wicket.stuff.jquery.plugin.effects.drop.JQDropPlugin/lib/effects.drop.js"></script> <script type="text/javascript" src="resources/com.noocodecommit.wicket.stuff.jquery.plugin.effects.explode.JQExplodePlugin/lib/effects.explode.js"></script> <script type="text/javascript" src="resources/com.noocodecommit.wicket.stuff.jquery.plugin.effects.fold.JQFoldPlugin/lib/effects.fold.js"></script> <script type="text/javascript" src="resources/com.noocodecommit.wicket.stuff.jquery.plugin.effects.JQAnimation/lib/effects.js"></script> <script type="text/javascript" src="resources/com.noocodecommit.wicket.stuff.jquery.plugin.effects.highlight.JQHighlightPlugin/lib/effects.highlight.js"></script> <script type="text/javascript" src="resources/com.noocodecommit.wicket.stuff.jquery.plugin.effects.pulsate.JQPulsatePlugin/lib/effects.pulsate.js"></script> <script type="text/javascript" src="resources/com.noocodecommit.wicket.stuff.jquery.plugin.effects.scale.JQScalePlugin/lib/effects.scale.js"></script> <script type="text/javascript" src="resources/com.noocodecommit.wicket.stuff.jquery.plugin.effects.shake.JQShakePlugin/lib/effects.shake.js"></script> <script type="text/javascript" src="resources/com.noocodecommit.wicket.stuff.jquery.plugin.effects.slide.JQSlidePlugin/lib/effects.slide.js"></script> <script type="text/javascript" src="resources/com.noocodecommit.wicket.stuff.jquery.plugin.effects.transfer.JQTransferPlugin/lib/effects.transfer.js"></script> <script type="text/javascript" src="resources/com.noocodecommit.wicket.stuff.jquery.plugin.ui.core.JQUiCorePlugin/lib/ui.core.js"></script> |
En utilisant la méthode [JQCore.init()], Wicket a lui même inséré les bons fichiers .js en gérant les dépendances entre les différents composants.
L’utilisation de cette méthode garantit qu’un script utilisant JQuery, JQueryUI ou n’importe quel effet visuel s’éxécutera correctement dans votre page.
Pour illustrer tout cela, nous allons tenter d’animer un élément de la page lors d’un click sur un lien.
Dans le code HTML de votre page, déclarez une div et un lien comme suit
|
1 2 3 4 5 |
<div style="height:50px;min-height:50px;"> <div wicket:id="block" style="border: 2px solid #0090DF;background-color: #68BFEF;width: 80px;height: 30px;"></div> </div> <br> <a wicket:id="effect1">Toggle Vertical</a> |
Dans le code java, dans le constructeur de la page ajoutez le code suivant
|
1 2 3 4 5 6 7 8 9 10 11 12 13 |
// -- cible de l'animation final Label block = new Label("block", "block"); block.setOutputMarkupId(true); add(block); // -- Effect toggle Vertical add(new AjaxLink("effect1") { public void onClick(AjaxRequestTarget target) { target.appendJavascript(JQAnimation.toggle(block, new JQBlind(JQBlindOptions.DIRECTION_VERTICAL))); } }); |
Compilez, puis lancez la page dans votre navigateur lorsque vous cliquez sur le lien, votre div s’anime.
Analyse
Nous allons d’abord nous intéresser à la source de la page générée par Wicket.
On remarque tout d’abord que Wicket a remplacé notre [wicket:id="block"] par un id unique.
Même chose pour notre lien [wicket:id="effect1"].
(note : l’id peut être différent sur votre page. L’important est de noter que Wicket a changé cette valeur.)
|
1 2 3 |
<div id="block3" class="drag">block</div> <br> <a id="effect14" onclick="var wcall=wicketAjaxGet(';jsessionid=C2842056B05C07AF433375040900EAB4?wicket:interface=:0:effect1::IBehaviorListener:0:',null,null, function() {return Wicket.$('effect14') != null;}.bind(this));return !wcall;" href="#">Hide Vertical</a> |
On peut également remarquer ; alors que dans notre page HTML nous n’avions rien renseigné de particulier par rapport à l’événement [onclick] du lien ; que celui ci est maintenant affecté à une action.
|
1 |
onclick="var wcall=wicketAjaxGet(';jsessionid=C2842056B05C07AF433375040900EAB4?wicket:interface=:0:effect1::IBehaviorListener:0:', null, null, function() {return Wicket.$('effect14') != null;}.bind(this)); return !wcall;" |
La couche ajax de Wicket utilise la fonction javascript [wicketAjaxGet()] pour effectuer des appels au serveur à partir de javascript.
C’est sur ce principe de base que fonctionne JQuery4Wicket.
Je m’attarderais plus en détail sur cette fonction dans un prochain post.
L’essentiel est de noter que cet appel javascript va déclencher sur le serveur l’éxécution d’une portion de code.
Pour nous il s’agit du code suivant
|
1 |
target.appendJavascript(JQAnimation.toggle(block, new JQBlind(JQBlindOptions.DIRECTION_VERTICAL))); |
Lorsque vous cliquez sur votre lien, le block s’anime.
Dans la fenetre WICKET AJAX DEBUG vous pouvez voir que Wicket a éxécuté un appel Ajax.
|
1 2 3 4 5 6 7 8 9 10 11 |
INFO: focus set on effect14 INFO: INFO: Initiating Ajax GET request on ;jsessionid=C2842056B05C07AF433375040900EAB4?wicket:interface=:0:effect1::IBehaviorListener:0:&random=0.21775740468311766 INFO: Invoking pre-call handler(s)... INFO: Received ajax response (172 characters) INFO: <?xml version="1.0" encoding="UTF-8"?><ajax-response><evaluate><![CDATA[$('#block3').toggle('blind', {direction:'vertical'}, 400, function(){});]]></evaluate></ajax-response> INFO: Response parsed. Now invoking steps... INFO: Response processed successfully. INFO: Invoking post-call handler(s)... INFO: Calling focus on effect14 INFO: focus set on wicketDebugLink |
On retrouve ici une trace de notre appel javascript vers le serveur
|
1 |
INFO: Initiating Ajax GET request on ;jsessionid=C2842056B05C07AF433375040900EAB4?wicket:interface=:0:effect1::IBehaviorListener:0:&random=0.21775740468311766 |
et également une trace du javascript que nous avons ajouté à la requete ajax.
|
1 |
INFO: <?xml version="1.0" encoding="UTF-8"?><ajax-response><evaluate><![CDATA[$('#block3').toggle('blind', {direction:'vertical'}, 400, function(){});]]></evaluate></ajax-response> |
C’est cette portion de code javascript qui a été éxécutée pour animer notre div.
La portion de code javascript qui utilise JQuery
|
1 |
$('#block3').toggle('blind', {direction:'vertical'}, 400, function(){}); |
est en réalité la traduction par JQuery4Wicket du code
|
1 |
JQAnimation.toggle(block, new JQBlind(JQBlindOptions.DIRECTION_VERTICAL)) |
dans l’absolu, nous aurions pu nous abstenir d’utiliser la classe JQAnimation et passer du javascript à la fonction [appendJavascript()]
|
1 |
target.appendJavascript("$('#" + block.getMarkupId() + "').toggle('blind', {direction:'vertical'}, 400, function(){});"); |
Conclusion
Félicitations, vous avez utilisé JQuery dans votre page web et pourtant vous n’avez pas écrit une seule ligne de javascript pour cela.
Avec une simple ligne de code ajoutée dans le constructeur de votre page, vous avez maintenant la possibilité d’ajouter du code javascript utilisant JQuery à vos requetes Wicket Ajax.
JQuery4Wicket n’en est qu’à ses débuts, mais avec l’aide de nicogiard, nous allons bosser pour améliorer encore le moteur et fournir de plus en plus de fonctionnalités.
Pour rappel, le site de démo se trouve ici
Imprimer cet article
Petite question à chaud : est-il possible de ne charger que les scripts JS dont on a besoin (genre core + dragndrop)?
Ce serait sympa de mettre un lien vers l’exemple final
Lien rajouté Grégo!
Concernant la question sur le chargement des scripts .js, JQuery4Wicket charge lui même une “base” qui permet de faire tourner un minimum de fonctions (cf : exemple dans le tutoriel). Effectivement ça fait un peu de pollution si tu n’as pas besoin de tout, mais c’est toujours moins pire en terme de poids total que de charger jquery + jquery.ui.all .
Lorsque tu auras besoin de faire du drag’n'drop, JQuery4Wicket fera le chargement pour toi en gérant les dépendances éventuelles.
Les ajouts par rapport à la base sont limités au strict minimum pour faire fonctionner le plugin voulu.
Enfin pour l’exemple final, tu le découvriras en faisant le tuto :p
Mais comme je sais que tu es une feignasse, je te file le lien direct vers le site de démo
http://www.noocodecommit.com/jquery4wicket/demo/blind
Hello,
Merci pour cette introduction fort utile
Sinon:
- Comptez vous rendre les sources disponibles ?
- N’avez vous pas envisagé d’utiliser une approche à base de builders au lieu de la surcharge ? quand on voit par exemple qu’il y’a 12 variantes de la méthode JQAnimation.show, ça fait peur
J’avais pensé à un truc fluide (Fluent Interfaces) du genre:
JQAnimation.component(block).animation(JQAnimation.ANIMATIONMODE_TOGGLE)
.direction(JQBlindOptions.DIRECTION_VERTICAL)
.duration(400).build(target);
Histoire de rester fidèle à l’esprit de JQuery et d’être plus lisible
- Pour les animations par exemple, pas moyen simple de les déclencher en local (pas d’Ajax) ? ça peut se faire par exemple en faisant :
effect2.add(new SimpleAttributeModifier(“onclick”, JQAnimation.show(block, new JQBlind(JQBlindOptions.DIRECTION_VERTICAL))));
add(effect2);
En fait non, maintenant que j’y pense, je crois que c’est la méthode la plus flexible, excepté peut être le fait d’ajouter un composant spécial qui correspond à un lien et qui joue sur le onclick.
Voili voilou.
Keep the cool stuff coming
Bonne idée concernant la notion de “Fluent Interface”, j’vais regarder ça prochainement histoire de voir si ça peut être intégrer rapidement.
On à déjà trouvé quelques axes d’amélioration, donc on va essayer de corriger tout ça.
Merci en tous cas Jawher pour avoir pris le temps de regarder le boulot de butcho!
Concernant la mise à dispo des sources, c’est prévu à plus ou moins court terme. Nicogiard et moi sommes actuellement en train de faire des ajustements au niveau de l’intégration des plugins JQuery. Lorsque la base sera saine, le code source sera publié je pense.
Pour ce qui est de l’approche ajax/non ajax, c’est au choix, JQuery4Wicket fournit juste une “traduction” en javascript. Libre a toi de l’utiliser dans le contexte qui t’arrange
Alors, après presque une semaine de travail acharné, nous avons, avec butcho, trouvé quelques petits loups dans la façon d’organiser les choses. Donc ça avance tranquillement, mais ça avance. Je pense qu’on va préparer un petit article pour dans pas longtemps, pour vous présenter les divers changements (et aussi pour avoir votre avis).
De plus j’ai presque une version intéressante de Fluent Interface, que j’ai fait pour la migration du plugin Lightbox. Je vous partage tout ça très vite (enfin si mon boulot ne me met pas à genoux)
Merci beaucoup pour cet exemple, cette librairie est destinée à un bel avenir je pense!
Merci pour ces encouragements Loic, n’hésite pas à nous faire part de tes suggestions et tes expériences avec JQuery4Wicket pour contribuer a son amélioration
Effectivement comme le dis nicogiard, nous sommes en train de revoir les mécanismes de fond sur la construction des plugins.
Dès que tout ca est à peu près stable, on vous en reparle.
Bonjour,
Je trouve votre travail fort intéressant.
Cependant en testant l’exemple drag’n drop, j’ai cette exception:
Unable to serialize class: com.noocodecommit.wicket.stuff.jquery.plugin.ui.draggable.JQDraggableOptions
Sachant que j’utilise la version 1.3.5 de wicket et la dernière version de Jquery4wicket.
Une idée de quoi cela peut venir?
PS: ce serait bien gentil de votre part de mettre les source en ligne. Le lien mis sur la page SVN ne marche pas :
svn checkout http://jquery4wicket.googlecode.com/svn/trunk/ jquery4wicket-read-only
Merci d’avance!
Salut, concernant le problème de serialization, je sais que j’ai eu des problèmes avec Ivy par exemple qui me chargeais les jar des sources pour mes dépendances. Exemple wicket-1.3.5.jar + wicket-1.3.5-src.jar.
Cela n’est très probablement pas ton cas. Peux tu éventuellement nous donner la trace compète ?
Concernant le projet, celui ci est un peu en stand by car nous sommes en train de fusionner avec le projet Wickext. Je ferais un post bientôt pour parler de cela plus en détail. Si tu souhaites vraiment les sources, je peux éventuellement te les envoyer par mail.
A+
Ca me dit bien d’avoir les sources, je vous en remercie d’avance.
Concernant la trace complète la voici:
[http-8080-1] ERROR [org.apache.wicket.util.lang.Objects] Error serializing object class wicketjpa.wicket.HelloWorld [object=[Page class = wicketjpa.wicket.HelloWorld, id = 0, version = 0]]
org.apache.wicket.util.io.SerializableChecker$WicketNotSerializableException: Unable to serialize class: com.noocodecommit.wicket.stuff.jquery.plugin.ui.draggable.JQDraggableOptions
Field hierarchy is:
0 [class=wicketjpa.wicket.HelloWorld, path=0]
private java.lang.Object org.apache.wicket.MarkupContainer.children [class=[Ljava.lang.Object;]
private java.lang.Object org.apache.wicket.MarkupContainer.children[0] [class=com.noocodecommit.wicket.stuff.jquery.plugin.ui.draggable.JQDraggable, path=0:draggable2-1]
private final com.noocodecommit.wicket.stuff.jquery.plugin.ui.draggable.JQDraggableOptions com.noocodecommit.wicket.stuff.jquery.plugin.ui.draggable.JQDraggable.options [class=com.noocodecommit.wicket.stuff.jquery.plugin.ui.draggable.JQDraggableOptions] <—– field that is not serializable
at org.apache.wicket.util.io.SerializableChecker.check(SerializableChecker.java:342)
at org.apache.wicket.util.io.SerializableChecker.checkFields(SerializableChecker.java:610)
at org.apache.wicket.util.io.SerializableChecker.check(SerializableChecker.java:533)
at org.apache.wicket.util.io.SerializableChecker.check(SerializableChecker.java:388)
at org.apache.wicket.util.io.SerializableChecker.checkFields(SerializableChecker.java:610)
at org.apache.wicket.util.io.SerializableChecker.check(SerializableChecker.java:533)
at org.apache.wicket.util.io.SerializableChecker.writeObjectOverride(SerializableChecker.java:678)
at java.io.ObjectOutputStream.writeObject(ObjectOutputStream.java:322)
at org.apache.wicket.util.io.IObjectStreamFactory$2.writeObjectOverride(IObjectStreamFactory.java:125)
at java.io.ObjectOutputStream.writeObject(ObjectOutputStream.java:322)
at org.apache.wicket.util.lang.Objects.objectToByteArray(Objects.java:1091)
at org.apache.wicket.protocol.http.pagestore.AbstractPageStore.serializePage(AbstractPageStore.java:197)
at org.apache.wicket.protocol.http.pagestore.DiskPageStore.storePage(DiskPageStore.java:811)
at org.apache.wicket.protocol.http.SecondLevelCacheSessionStore$SecondLevelCachePageMap.put(SecondLevelCacheSessionStore.java:332)
at org.apache.wicket.Session.requestDetached(Session.java:1370)
at org.apache.wicket.RequestCycle.detach(RequestCycle.java:1085)
at org.apache.wicket.RequestCycle.steps(RequestCycle.java:1372)
at org.apache.wicket.RequestCycle.request(RequestCycle.java:493)
at org.apache.wicket.protocol.http.WicketFilter.doGet(WicketFilter.java:355)
at org.apache.wicket.protocol.http.WicketFilter.doFilter(WicketFilter.java:200)
at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:235)
at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:206)
at org.apache.catalina.core.StandardWrapperValve.invoke(StandardWrapperValve.java:233)
at org.apache.catalina.core.StandardContextValve.invoke(StandardContextValve.java:191)
at org.apache.catalina.core.StandardHostValve.invoke(StandardHostValve.java:128)
at org.apache.catalina.valves.ErrorReportValve.invoke(ErrorReportValve.java:102)
at org.apache.catalina.core.StandardEngineValve.invoke(StandardEngineValve.java:109)
at org.apache.catalina.connector.CoyoteAdapter.service(CoyoteAdapter.java:286)
at org.apache.coyote.http11.Http11Processor.process(Http11Processor.java:845)
at org.apache.coyote.http11.Http11Protocol$Http11ConnectionHandler.process(Http11Protocol.java:583)
at org.apache.tomcat.util.net.JIoEndpoint$Worker.run(JIoEndpoint.java:447)
at java.lang.Thread.run(Thread.java:619)
Caused by: java.io.NotSerializableException: com.noocodecommit.wicket.stuff.jquery.plugin.ui.draggable.JQDraggableOptions
at java.io.ObjectOutputStream.writeObject0(ObjectOutputStream.java:1156)
at java.io.ObjectOutputStream.defaultWriteFields(ObjectOutputStream.java:1509)
at java.io.ObjectOutputStream.writeSerialData(ObjectOutputStream.java:1474)
at java.io.ObjectOutputStream.writeOrdinaryObject(ObjectOutputStream.java:1392)
at java.io.ObjectOutputStream.writeObject0(ObjectOutputStream.java:1150)
at java.io.ObjectOutputStream.writeArray(ObjectOutputStream.java:1338)
at java.io.ObjectOutputStream.writeObject0(ObjectOutputStream.java:1146)
at java.io.ObjectOutputStream.defaultWriteFields(ObjectOutputStream.java:1509)
at java.io.ObjectOutputStream.writeSerialData(ObjectOutputStream.java:1474)
at java.io.ObjectOutputStream.writeOrdinaryObject(ObjectOutputStream.java:1392)
at java.io.ObjectOutputStream.writeObject0(ObjectOutputStream.java:1150)
at java.io.ObjectOutputStream.writeObject(ObjectOutputStream.java:326)
at org.apache.wicket.util.io.IObjectStreamFactory$2.writeObjectOverride(IObjectStreamFactory.java:117)
… 23 more
Nadim, pourrais tu nous donner la déclaration de ta JQDraggable ? Je suis curieux de savoir quelle option génère cette erreur.
Merci