This page (revision-6) was last changed on 22-Nov-2017 10:56 by Dieter Käppel

This page was created on 17-Mar-2017 11:26 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
6 22-Nov-2017 10:56 19 KB Dieter Käppel to previous
5 22-Nov-2017 10:56 19 KB Dieter Käppel to previous | to last
4 26-Mar-2017 10:37 18 KB Dieter Käppel to previous | to last
3 26-Mar-2017 10:32 17 KB Dieter Käppel to previous | to last
2 26-Mar-2017 10:16 13 KB Dieter Käppel to previous | to last
1 17-Mar-2017 11:26 7 KB Dieter Käppel to last

Page References

Incoming links Outgoing links

Version management

Difference between version and

At line 3 added 5 lines
__Achtung:__ [JSF-JQuery 2] wurde durch [JQueryWidget2] abgelöst. Verwenden Sie jetzt [JQueryWidget2], um noch kompatibler und effizienter [JQuery] mit [JSF] zu kombinieren.
!!!Inhalt
[{TableOfContents title='Page contents' numbered='true'}]
At line 73 changed one line
!!!JQueryResourceHandler
!!Options
In der Regel bedarf es einiger Optionen, mit denen das Widget gesteuert werden kann. Dazu gibt es mehrere Mechanismen, mit der Tag-Attribute, Attribut-Tags oder Behaviors übergeben werden können.
!Default Options
Eine Reihe von Options sind bereits im JQueryWidget selbst implementiert, weil diese häufig benötigt werden:
||Option||Typ||Wert||Erklärung
|url|custom|getUrl()|Der Kanal über den das Widget mit dem Server kommuniziert. Dieser sollte nur geändert werden, wenn man einen eigenen Resource-Handler implementieren möchte. Dafür sollte man einen guten Grund haben.
|dataType|property|script|Legt den Mime-Type fest, mit dem das Widget mit dem Server kommuniziert. Mögliche Werte sind script, json, xml oder text. Die Funktionalität der Widget-Funktionen sind allerdings nur im Default gewährleistet. Andernfalls sind entsprechende Funktionen zu überschreiben.
Weitere Optionen werden nicht an das Widget übergeben, aber direkt an den vom Java-Code generierten XHTML-Code:
||Option||Typ||Wert||Erklärung
|style|property|empty|Mit diesem Tag-Attribut oder Property können Style-Informationen an das Top-Level DIV-Element des Widgets übergeben werden.
|styleClass|property|getWidgetStyleClass()|Dieses Attribut oder Property übergibt Style-Klassen an das Widget. Default ist, die Methode getWidgetStyleClass() aufzurufen, deren Default-Wert wiederum ist j-<lower widget name>, also der Class-Name des Widget in Kleinschrift.
!Property Options
Dazu kann die Methode getOptions überschrieben werden:
{{{
@Override
public String getOptions(Object... properties) {
return super.getOptions("customOption");
}
}}}
Alle hier angegebenen Properties werden als Java-Properties der Java-Component an das Javascript-Widget übergeben. Die Implementierung auf der Java-Seite erfolgt im typischen JSF-Style:
{{{
public String getCustomOption() {
return (String)getStateHelper().eval("customOption");
}
public void setCustomOption(String customOption) {
getStateHelper().put("customOption", customOption);
}
}}}
Beispiel:
{{{
<j:test customOption="some option"/>
}}}
__Hinweis:__ Jede Option kann ebenfalls eine EL-Expression enthalten.
!Behavior Options
Alle dem Tag untergeordneten Behaviors, also beispielsweise <p:ajax> oder <e:behavior> werden dem Javascript-Widget in Form von Javascript-Funktionen übergeben:
{{{
<j:autocomplete id="autocomplete" value="#{jqueryController.value}" complete="#{jqueryController.complete}">
<p:ajax event="change" listener="#{jqueryController.action}"/>
</j:autocomplete>
}}}
__Erklärung:__ Das Javascript-Widget implementiert den Event "change". Dieser kann dann auf der XHTML-Seite durch einen entsprechenden Client-Behavior Tag verarbeitet werden, wie das von Tags, wie <h:inputText> gewohnt ist.
!Parameter Options
Eine weitere Möglichkeit zur Übergabe von Optionen ist die Param-Tag-Familie mit den Implementierungen <f:param>, <j:param>, <j:function>:
* __<f:param>:__ Der standardmäßige Parameter-Tag übergibt das Name-Value-Paar 1:1 via JSON an das Widget. Der Value darf dabei eine EL Value-Expression darstellen und ein komplexes Objekt enthalten, das natürlich JSON serialisierbar sein muss. Dabei können Jackson-Annotationen verwendet werden, um die Serialisierung zu steuern. Insbesondere darf auch das Interface JsonSerializable implementiert werden und die von Jackson mitgelieferte Variante RawValue genutzt werden.
* __<j:function>:__ Dieser Parameter übergibt eine Javascript-Funktion. Da <f:param> die Werte immer zu Strings macht, kann man mit <f:param> keine Javascript-Parameter übergeben, man braucht daher einen anderen Tag, wie eben <j:function>. Dieser Tag unterstützt das Attribut arguments, um die Komma seperierte der Javascript Argumente zu definieren. Der Javascript-Code kann sich sowohl im Value-Attribut (wenig Code) oder im Text-Body des Tags (viel Code) befinden. Für größeren Code sollte man ohnehin eine Javascript-Datei schreiben und aus dem Tag nur referenzieren.
* __<j:param>:__ Mit diesem Tag kann der Value frei übergeben werden. Der Tag sollte nur als allerletzte Lösung verwendet werden, weil dadurch die Gefahr von ungültigem JSON-Code entsteht, der zu einem Javascript-Fehler führt und die Ausführung der Web-Seite verhindert.
Beispiel:
{{{
<j:autocomplete id="autocomplete" value="#{jqueryController.value}" complete="#{jqueryController.complete}">
<p:inputText id="input" autocomplete="off"/>
<j:function name="cellRenderer", arguments="$row, key, value">
if (key == "styleClass") {
$row.addClass(value);
} else {
var $cell = $("<td/>");
$cell.attr("title", value);
$cell.html(value);
if (key == "label") {
$cell.css("background-color", "black");
$cell.css("color", "yellow");
}
$row.append($cell);
}
</j:function>
</j:autocomplete>
}}}
!Custom Options
Die einfachste Möglichkeit um dynamisch berechnete Optionen hinzuzufügen ist es, ein Property-Option zu definieren und den Getter zu implementieren. Aber es gibt noch eine weitere Methode, mit der man Options hinzufügen kann:
{{{
public void addWidgetOptions(Map<String, Object> options) {
options.put("name", "value");
}
}}}
!!!Styling
Wie beim Property styleClass bereits beschrieben, erhält das Top-Level-DIV des Widgets die Style-Class j-<lower widget name>. Wenn die Widget-Klasse also Autocomplete heißt, bekommt sie die Style-Class j-autocomplete. Damit dürfte ein Großteil der Styling-Regeln im CSS behandelbar sein.
Beispiel:
{{{
.j-autocomplete > .j-autocomplete-panel {
display: none;
z-index: 1;
max-height: 300px;
overflow-x: hidden;
overflow-y: auto;
white-space: nowrap;
}
}}}
!!!Server Requests
At line 284 added 233 lines
!!Vis-Network
Vis-Network ist eine Javascript-Bibliothek zum Rendern von Netzwerkdiagrammen mittels HTML5. Im Folgenden ist das entsprechende JQueryWidget aufgezeigt, mit dem die Bibliothenk in JSF integriert wird.
Die Komponente:
{{{
@FacesComponent(namespace = JQueryComponent.NAMESPACE, createTag = true)
@ResourceDependencies({
@ResourceDependency(name = "jquery/jquery.js", library = "primefaces"),
@ResourceDependency(name = "jsf-jquery.js", library = "jquery-js"),
@ResourceDependency(name = "vis.min.js", library = "jquery-js"),
@ResourceDependency(name = "vis-network.js", library = "jquery-js"),
@ResourceDependency(name = "vis.min.css", library = "jquery-css")
})
public class VisNetwork extends JQueryWidget implements ClientBehaviorHolder {
public static class Position {
private int x;
private int y;
public int getX() {
return x;
}
public void setX(int x) {
this.x = x;
}
public int getY() {
return y;
}
public void setY(int y) {
this.y = y;
}
}
public static class NodeEvent extends AjaxBehaviorEvent {
private static final long serialVersionUID = 1L;
private Node node;
private Position position;
public NodeEvent(UIComponent component, Behavior behavior) {
super(component, behavior);
setPhaseId(PhaseId.INVOKE_APPLICATION);
}
public Node getNode() {
return node;
}
public void setNode(Node node) {
this.node = node;
}
public Position getPosition() {
return position;
}
public void setPosition(Position position) {
this.position = position;
}
@Override
public boolean isAppropriateListener(FacesListener facesListener) {
return (facesListener instanceof AjaxBehaviorListener);
}
@Override
public void processListener(FacesListener listener) {
if (listener instanceof AjaxBehaviorListener) {
((AjaxBehaviorListener)listener).processAjaxBehavior(this);
}
}
}
public static final String DEFAULT_EVENT = "click";
public static final Collection<String> EVENT_NAMES = Arrays.asList(DEFAULT_EVENT);
public Boolean getHover() {
return (Boolean)getStateHelper().eval("hover");
}
public void setHover(Boolean hover) {
getStateHelper().put("hover", hover);
}
public String getShape() {
return (String)getStateHelper().eval("shape");
}
public void setShape(String shape) {
getStateHelper().put("shape", shape);
}
public String getBackground() {
return (String)getStateHelper().eval("background");
}
public void setBackground(String background) {
getStateHelper().put("background", background);
}
public String getBorder() {
return (String)getStateHelper().eval("border");
}
public void setBorder(String border) {
getStateHelper().put("border", border);
}
public String getColor() {
return (String)getStateHelper().eval("color");
}
public void setColor(String color) {
getStateHelper().put("color", color);
}
public String getOnclick() {
return (String)getStateHelper().eval("onclick");
}
public void setOnclick(String onclick) {
getStateHelper().put("onclick", onclick);
}
@Override
public Collection<String> getEventNames() {
return EVENT_NAMES;
}
@Override
public String getDefaultEventName() {
return DEFAULT_EVENT;
}
@Override
public String getOptions(Object... properties) {
return super.getOptions("value", "shape", "background", "border", "color", "click");
}
public Node getNode(String id) {
if (id == null)
return null;
for (Node node : ((Network)getValue()).getNodes()) {
if (id.equals(node.getId()))
return node;
}
return null;
}
@Override
public void queueEvent(FacesEvent event) {
Map<String, String> params = getFacesContext().getExternalContext().getRequestParameterMap();
NodeEvent nodeEvent = new NodeEvent(this, ((BehaviorEvent)event).getBehavior());
nodeEvent.setNode(getNode(params.get(getClientId() + ":node")));
nodeEvent.setPosition(JQueryHelper.fromJson(params.get(getClientId() + ":position"), Position.class));
nodeEvent.setPhaseId(event.getPhaseId());
super.queueEvent(nodeEvent);
}
}
}}}
Das JQuery-Widget:
{{{
$.widget("ext.VisNetwork", $.ext.JQueryWidget, {
options: {
hover: true,
shape: "box",
background: "#d7ebf9",
border: "#aed0ea",
color: "#2779aa"
},
_create: function() {
this._super();
this.render();
},
_destroy: function() {
this.cleanup();
this._super();
},
render: function() {
this.cleanup(); // TODO update possible?
this.network = this.createNetwork(this.options.value);
var widget = this;
this.network.on("click", function(param) {
widget.onclick(param);
});
},
cleanup: function() {
if (this.network) {
this.network.off("click");
this.network.destroy();
this.network = null;
}
},
createNetwork: function(data) {
return new vis.Network(this.element[0], data, {
interaction: {
hover: this.options.hover
},
nodes: {
shape: this.options.shape,
color: {
background: this.options.background,
border: this.options.border
},
font: {
color: this.options.color
}
}
});
},
onclick: function(param) {
if (param.nodes.length != 0) {
var data = {};
data[this.element.attr("id") + ":node"] = param.nodes;
data[this.element.attr("id") + ":position"] = $.stringify(param.pointer.DOM);
this.ajaxParam(data);
this.options.click(param);
}
},
onsuccess: function(request, response, options) {
this.network.setData(response);
this.network.redraw();
}
});
}}}
__Erklärung:__ Die Daten für die eigentliche Grafik werden synchorn mit den Options im HTML-Code durch JSF herausgerendert und im HTTP-Dokument-Request übertragen. Natürlich könnte man auch hier über die Action-Funktion gehen und asynchron nachladen, wie dies im Beispiel für Anychart beschrieben wurde. Die Action-Funktion wird hier jedoch für das Klicken auf die Netzwerkknoten genutzt. Daraus wird eine Faces-Behavior erzeugt, mit der man weitere Elemente auf der JSF-Seite steuern kann.
JSF-Seitig sieht es dann so aus:
{{{
<j:visNetwork id="net" value="#{visNetworkController.network}" style="height: 600px;">
<p:ajax listener="#{visNetworkController.action}" update="@this"/>
</j:visNetwork>
}}}