This page (revision-7) was last changed on 16-Aug-2019 11:55 by Dieter Käppel

This page was created on 16-Aug-2019 08:38 by Dieter Käppel

Only authorized users are allowed to rename pages.

Only authorized users are allowed to delete pages.

Page revision history

Version Date Modified Size Author Changes ... Change note
7 16-Aug-2019 11:55 14 KB Dieter Käppel to previous
6 16-Aug-2019 11:55 14 KB Dieter Käppel to previous | to last
5 16-Aug-2019 11:54 12 KB Dieter Käppel to previous | to last
4 16-Aug-2019 11:35 12 KB Dieter Käppel to previous | to last
3 16-Aug-2019 11:30 9 KB Dieter Käppel to previous | to last
2 16-Aug-2019 09:43 1 KB Dieter Käppel to previous | to last
1 16-Aug-2019 08:38 1 KB Dieter Käppel to last

Page References

Incoming links Outgoing links

Version management

Difference between version and

At line 1 changed one line
[JQueryWidget2] ist das neue Werkzeug, um noch effizienter das am weitesten verbreitete Browser-Framework [JQuery] mit dem am weitesten verbreiteten Business-Framework [|Java Server Faces|JSF] zu kombinieren.
[JQueryWidget2] ist das neue Werkzeug, um noch effizienter das am weitesten verbreitete Browser-Framework [JQuery] mit dem am weitesten verbreiteten Business-Framework [|Java Server Faces|JSF] und [Microservices|Microservice] zu kombinieren.
At line 16 added 234 lines
!!!Documentation
Im Folgenden wird die API von [JQueryWidget2] dokumentiert.
!!Events
Events können standardmäßig wie in [JSF2] verwendet werden. Dazu werden zunächst die entsprechenden Methoden der UIComponent implementiert:
{{{
public static final String DEFAULT_EVENT = "timeout";
public static final Collection<String> EVENT_NAMES = Arrays.asList(DEFAULT_EVENT);
@Override
public Collection<String> getEventNames() {
return EVENT_NAMES;
}
@Override
public String getDefaultEventName() {
return DEFAULT_EVENT;
}
}}}
Diese Events können später von Tags empfangen werden, wie <j:behavior> oder <p:ajax>.
[JQueryWidget2] sendet die entsprechenden [Javascript] Funktionen direkt an die [JQuery] Komponente, sodass diese Events im [Javascript] Code aufgerufen werden können:
{{{
if (widget.options.timeout)
widget.options.timeout();
}}}
Vorher wird abgefragt, ob eine Funktion für diesen Code geliefert wurde. In der Regel ist die Nutzung der Events optional.
!!Elements
Eine komplexe Komponente besteht oft aus mehreren Teilen. Diese Teile möchte man getrennt updaten können, Daten mit unterschiedlichen Modellen austauschen können und unterschiedliche Events auslösen. Möchte man Elemente verwendet, implementiert man zunächst NamingContainer in der Komponente:
{{{
@FacesComponent(namespace = JQueryWidget2.NAMESPACE, createTag = true)
@ResourceDependencies({
@ResourceDependency(name = "jquery/jquery.js", library = "primefaces"),
@ResourceDependency(name = "jsf-jquery.js", library = "jquery-js"),
@ResourceDependency(name = "jquery.throttle.min.js", library = "jquery-js"),
@ResourceDependency(name = "matrix.js", library = "jquery-js"),
@ResourceDependency(name = "matrix.css", library = "jquery-css")
})
public class Matrix extends JQueryWidget2 implements NamingContainer {
[...]
}
}}}
Damit ist es möglich, der Komponente einzelne HTML-Tags hinzuzufügen, die dann ein eindeutiges Prefix besitzen. Dazu wird die Methode addElements überschrieben:
{{{
@Override
public void addElements(List<UIComponent> elements) {
elements.add(new WidgetElement<String>("table") {});
}
}}}
__Hinweis:__ WidgetElement ist die einfachste Klasse zum Implementieren eines Elements. Da es sich um eine generische Klasse mit einem Typ-Parameter handelt, muss der Typ-Parameter spezifiziert werden. Da dieser in dem Beispiel nicht wirklich benötigt wird, geben wir hier String an.
Dadurch wird folgender HTML-Code geschrieben:
{{{
<span id="form:matrix" class="j-matrix" style="height: 500px;">
<span id="form:matrix:table" class="j-matrix-table"/>
</span>
}}}
Das Element erhält eine Id, die sich aus der Client-Id des [JQueryWidget2] zusammensetzt zuzüglich des Namens des Elements selbst: "<client-id>:table".
Im [Javascript] Code wird dann über das Property elements auf die Elemente zugegriffen, also mit this.elements.table. Darin befindet sich unter anderem das HTML-Element ([JQuery]-gewrappt):
{{{
this.elements.table.element()
}}}
Damit kann man bequem alle möglichen Operationen auf dem Element des Widgets ausführen.
!!AJAX Requests
Um einen [JSF2] konformen AJAX-Request auszuführen, wird ein Element vom Typ WidgetBehavior verwendet.
{{{
@Override
public void addElements(List<UIComponent> elements) {
elements.add(new WidgetBehavior<String>("table") {});
}
}}}
__Hinweis:__ Hier wird die Klasse WidgetBehavior implementiert. Der Typparameter erfüllt hier die Aufgabe, den Typ des AJAX-Models festzulegen. Aufgrund der Einfachheit verwenden wir hier wieder String.
JSF verwendet zum Abschicken des Requests immer ein Element mit einer Client-Id. Um bestimmte Operationen auszuführen, wird auch ein Element upgedatet. Die Grundeinstellung bei [JQueryWidget2] ist, dass das Element sowohl den AJAX-Request abschickt, als auch upgedated wird. So braucht man zunächst keinerlei Konfiguration vorzunehmen, AJAX läuft also "out of the box":
{{{
this.elements.table.request()
}}}
Auf der Java-Seite können wir den Aufruf nun empfangen mit:
{{{
@Override
public void addElements(List<UIComponent> elements) {
elements.add(new WidgetBehavior<String>("table") {
@Override
public void invokeApplication() {
System.out.println("table was invoked");
}
});
}
}}}
WidgetBehavior besitzt folgende Methoden, um den JSF-Lifecycle abzubilden:
{{{
void decodeData(T data)
void invokeApplication()
void encodeContent(FacesContext context) throws IOException
Object encodeData()
}}}
||Methode||Bedeutung
|decodeData|Hier werden die vom Javascript gesendeten JSON-Daten fertig deserialisiert als Java-Objekt geliefert
|invokeApplication|Aufruf in der Invoke Application Phase
|encodeContent|Hier kann HTML-Content des Elements geschrieben werden
|encodeData|Hier kann ein Java-Objekt in der Form von JSON-Daten an den Javascript-Code zurückgegeben werden
Auf der [Javascript] Seite sieht die API dann folgendermaßen aus:
{{{
this.elements.table.request({
data: "Hello",
callback: function(data) {
console.log("Response: " + data);
}
});
}}}
Es können also zwei unterschiedliche Klassen für den AJAX-Aufruf und die AJAX-Antwort verwendet werden. Sowohl Request-Parameter als auch Response-Parameter sind jeweils optional und können bei Bedarf verwendet werden. Werden sie nicht gebraucht, können die entsprechenden Methoden einfach weggelassen werden.
Der AJAX-Aufruf erfolgt asynchron. Die Daten werden durch das Property "data" mitgegeben. In unserem Beispiel entspricht der Datentyp String. Es kann hier jede JSON-Deserialisierbares Java-Klasse verwendet werden. Die Antwort erfolgt in der Form eines Callbacks, da die Antwort asynchron kommt. Dazu übergeben wie die Callback-Funktion durch das Property "callback". Die Funktion kann optional das Argument "data" haben, welches dann die AJAX-Response bringt.
||Daten||Javascript||Java
|Request|data|decodeData(T data)
|Response|callback(data)|Object encodeData()
__Hinweis:__ Die AJAX-Response Methode in Java hat den Rückgabetyp Object. Dieser kann beim Überschreiben auf eine Klasse festgelegt werden. Allerdings kann auch weiterhin Object verwendet werden, da die JSON-Serialisierung die Klasse aus dem tatsächlich zurückgegebenen Objekt verwendet.
!!!Beispiele
Die folgenden Beispiele verdeutlichen den Einsatz des [JQueryWidget2].
!!Timer
Der Java-Code für die Komponente:
{{{
@FacesComponent(namespace = AppComponent.NAMESPACE, createTag = true)
@ResourceDependencies({
@ResourceDependency(name = "jquery/jquery.js", library = "primefaces"),
@ResourceDependency(name = "jsf-jquery.js", library = "jquery-js"),
@ResourceDependency(name = "jquery.countdown.min.js", library = "js"),
@ResourceDependency(name = "timer.js", library = "js")
})
public class Timer extends JQueryWidget2 {
public static final String DEFAULT_EVENT = "timeout";
public static final Collection<String> EVENT_NAMES = Arrays.asList(DEFAULT_EVENT);
@Override
public Collection<String> getEventNames() {
return EVENT_NAMES;
}
@Override
public String getDefaultEventName() {
return DEFAULT_EVENT;
}
public Integer getTime() {
return (Integer)getStateHelper().eval("time");
}
public void setTime(Integer time) {
getStateHelper().put("time", time);
}
public String getFormat() {
return (String)getStateHelper().eval("format");
}
public void setFormat(String format) {
getStateHelper().put("format", format);
}
public String getOntimeout() {
return (String)getStateHelper().eval("ontimeout");
}
public void setOntimeout(String ontimeout) {
getStateHelper().put("ontimeout", ontimeout);
}
@Override
public String getOptions(Object... properties) {
return super.getOptions("time", "format", "timeout");
}
}
}}}
Der Javascript-Code für die JQuery-Komponente:
{{{
//# sourceURL=timer.js
// Documentation: http://hilios.github.io/jQuery.countdown/documentation.html
$.widget("ext.Timer", {
options: {
format: "%M:%S"
},
_create: function() {
this._super();
var widget = this;
this.element.on("update.countdown", function(event) {
widget.element.text(event.strftime(widget.options.format));
});
this.element.on("finish.countdown", function(event) {
if (widget.options.timeout)
widget.options.timeout();
widget.start();
});
if (this.options.time)
this.start();
},
start: function() {
this.element.countdown(Date.now() + 1000 * this.options.time);
}
});
}}}