JSF meets JS (2. ed.)
JSF-Komponenten mit JavaScript
Sven Kölpin
open knowledge GmbH
Herbstcampus 2015 – JSF meets Javascript 2. ed 2
JSF in Webanwendungen?
Herbstcampus 2015 – JSF meets Javascript 2. ed 3
JavaScript & SPA
• Single page application (SPA)
• Nur eine HTML-Seite
• DOM-Manipulation hintergründig
• Business-Logik im Client
• Status im Browser
• Rolle des Servers
• Stateless
Herbstcampus 2015 – JSF meets Javascript 2. ed 4
JavaScript & SPA
• Hypegefahr
• „Is angularJs dead?“
• „ReactJs is the next big thing!“
• Architekturelle Probleme
• Geschwindigkeit
• Browserkompatibilität
• Pitfalls
• Pionierarbeit (v.a. Enterpriseumfeld)
Herbstcampus 2015 – JSF meets Javascript 2. ed 5
Serverseitige Webanwendungen
• Berüchtigt im Enterprise Umfeld
• Bekanntes Programiermodell
• Weniger Medienbrüche
• Rich Internet Applications
• Ajax
• Presentations-Logik
• Rolle von JavaScript
• DOM-Manipulation
Herbstcampus 2015 – JSF meets Javascript 2. ed 6
Serverseitige Webanwendungen
• Berüchtigt im Enterprise Umfeld
• Bekanntes Programiermodell
• Weniger Medienbrüche
• Rich Internet Applications
• Ajax
• Presentations-Logik
• Rolle von JavaScript
• DOM-Manipulation
 BEST OF BREED
Herbstcampus 2015 – JSF meets Javascript 2. ed 7
JSF meets JavaScript
Herbstcampus 2015 – JSF meets Javascript 2. ed 8
JSF meets JS: Why not Primefaces?
Herbstcampus 2015 – JSF meets Javascript 2. ed 9
JSF meets JS: Why not Primefaces?
• Kundenanforderungen an die GUI
• Individuelle Probleme
• Frameworks sind Blackboxes
• Third-Party-Libraries
• Boilerplate
• Bugs
• Abhängigkeiten
Herbstcampus 2015 – JSF meets Javascript 2. ed 10
Ziele des Vortrags
• Best-Practices vermitteln
• JavaScript-Pattern
• JSF-JS-Komponenten
• JSF-JavaScript-
Kommunikation
→ Den Einsatz von 3rd Party Libraries überdenken
Herbstcampus 2015 – JSF meets Javascript 2. ed 11
Was im Standard geschah...
Herbstcampus 2015 – JSF meets Javascript 2. ed 12
JSF Composite Components
• JSF-Code in Komponenten auslagern
• Parametrisierbar
• Wiederverwendbar
• Ziel: deklarative Kapselung von GUI-Logik
<html xmlns="http://www.w3.org/1999/xhtml"
xmlns:ok="http://xmlns.jscp.org/jsf/composite/ok">
<ok:labelTextBox
value="#{someBean.firstName}"
name="Firstname">
</ok:labelTextBox>
Herbstcampus 2015 – JSF meets Javascript 2. ed 13
JSF Composite Components
• „Keep simple things simple“
• XHTML Interface
• XHTML Implementierung
• „Convention over code & configuration“
• Namenskonventionen
• Ressourcenzugriff
Herbstcampus 2015 – JSF meets Javascript 2. ed 14
Keep simple things simple
• Interface & Implementierung
<html xmlns="http://www.w3.org/1999/xhtml"
xmlns:composite="http://java.sun.com/jsf/composite"
xmlns:jsf="http://xmlns.jcp.org/jsf">
<composite:interface>
<composite:attribute name="name" />
<composite:attribute name="value"/>
</composite:interface>
<composite:implementation>
<label jsf:id="lbl" jsf:for="inputComponent"
jsf:value="#{cc.attrs.name}"/>
<input type="text" jsf:id="inputComponent"
jsf:value="#{cc.attrs.value}"/>
</composite:implementation>
Herbstcampus 2015 – JSF meets Javascript 2. ed 15
Convention over configuration
• webapp/resources/ok/labelTextBox.xhtml
 xmlns:ok="http://xmlns.jcp.org/jsf/composite/ok"
<html xmlns="http://www.w3.org/1999/xhtml"
xmlns:composite="http://java.sun.com/jsf/composite"
xmlns:jsf="http://xmlns.jcp.org/jsf">
<composite:interface>
<composite:attribute name="name" />
<composite:attribute name="value"/>
</composite:interface>
<composite:implementation>
<label jsf:id="lbl" jsf:for="inputComponent"
jsf:value="#{cc.attrs.name}"/>
<input type="text" jsf:id="inputComponent"
jsf:value="#{cc.attrs.value}"/>
</composite:implementation>
Herbstcampus 2015 – JSF meets Javascript 2. ed 16
Und JavaScript?
Herbstcampus 2015 – JSF meets Javascript 2. ed 17
JSF und JS: Der Standard
• Alles ist deklarativ in JSF (XML-Kapselung)
• Komponenten
• JavaScript
• Standardisierte JavaScript-Integration: Clientbehaviors
<h:dataTable value="#{someBean.list}" var="row">
<h:column>#{row.valA}</h:column>
<h:column>#{row.valB}</h:column>
</h:dataTable>
<h:commandButton value="Submit">
<f:ajax execute="@this" render="panelB"/>
</h:commandButton>
Herbstcampus 2015 – JSF meets Javascript 2. ed 18
Client Behaviors
• JavaScript deklarativ kapseln
• Ähnlich zu <f:ajax/> - Tag
• Komponenten um clientseitige Funktionalität erweitern
<html xmlns="http://www.w3.org/1999/xhtml"
xmlns:okb="http://openknowledge.de/behavior" ...>
<input type="submit" jsf:id="submit" value="Submit this">
<okb:confirm message="Are you sure?"/>
<f:ajax render="parentForm"/>
</input>
Herbstcampus 2015 – JSF meets Javascript 2. ed 19
Client Behaviors
• JavaScript deklarativ kapseln
• Ähnlich zu <f:ajax/> - Tag
• Komponenten um clientseitige Funktionalität erweitern
<html xmlns="http://www.w3.org/1999/xhtml"
xmlns:okb="http://openknowledge.de/behavior" ...>
<input type="submit" jsf:id="submit" value="Submit this">
<okb:confirm message="Are you sure?"/>
<f:ajax render="parentForm"/>
</input>
Herbstcampus 2015 – JSF meets Javascript 2. ed 20
Client Behaviors
• Was passiert da?
<input id="parentForm:submit"
onclick="jsf.util.chain(this,event,
'return confirm('Are you sure?')',
'mojarra.ab(this,event,'action',0,'parentForm')');"/>
<input type="submit" jsf:id="submit" value="Submit this">
<okb:confirm message="Are you sure?"/>
<f:ajax render="parentForm"/>
</input>
Herbstcampus 2015 – JSF meets Javascript 2. ed 21
Client Behaviors
• Was braucht man?
• Behavior-Klasse
• extends ClientBehaviorBase
• @FacesBehavior(“de.my.behavior“)
• taglib.xml
• Konfiguration 
• JavaScript-Code
• Das eigentliche Herzstück
Herbstcampus 2015 – JSF meets Javascript 2. ed 22
Client Behaviors
@FacesBehavior("de.openknowledge.SimpleBehavior")
public class SimpleBehavior extends ClientBehaviorBase {
private String message;
@Override
public String getScript(ClientBehaviorContext behaviorContext) {
return "return confirm('“+getMessage()+“')";
}
public String getMessage() {
return message;
}
public void setMessage(String msg) {
this.message = msg;
}
...
Herbstcampus 2015 – JSF meets Javascript 2. ed 23
Client Behaviors
• JavaScript in Java?
@FacesBehavior("de.openknowledge.SimpleBehavior")
@ResourceDependencies(value = {
@ResourceDependency(name = "ok/confirm.js")
})
public class SimpleBehavior extends ClientBehaviorBase {
private String message;
@Override
public String getScript(ClientBehaviorContext behaviorContext) {
return "ok.confirmDialog.show();";
}
...
}
Herbstcampus 2015 – JSF meets Javascript 2. ed 24
Client Behaviors
• META-INF/ok.taglib.xml
<facelet-taglib version="2.2" … >
<namespace>http://openknowledge.de/behavior</namespace>
<tag>
<tag-name>confirm</tag-name>
<behavior>
<behavior-id>
de.openknowledge.SimpleBehavior
</behavior-id>
</behavior>
<attribute>
<name>message</name>
</attribute>
</tag> ...
Herbstcampus 2015 – JSF meets Javascript 2. ed 25
Client Behaviors
• Zeitgemäß?
• Konfiguration 
• Boilerplate 
• Eventbasiert 
• Keine zwingenden JS-Pattern
Herbstcampus 2015 – JSF meets Javascript 2. ed 26
JSF & JavaScript – Ein Chaos vermeiden
Herbstcampus 2015 – JSF meets Javascript 2. ed 27
JSF & JavaScript
• Umittelbare Integration von JavaScript in JSF
• Nicht standardisiert
• Inline Scripting
<input type="text" jsf:id="dp"/>
<script type="text/javascript">
var dpElm = document.getElementById("form:dp");
dpElm.dataset.datepicker = true;
dpElm.dataset.dateformat = #{someBean.dateformat};
//...
</script>
<div jsf:id="someOtherPanel">
<h1>Bad bad code...</h1>
</div>
Herbstcampus 2015 – JSF meets Javascript 2. ed 28
JSF & JavaScript
• Umittelbare Integration von JavaScript in JSF
• Nicht standardisiert
• Inline Scripting
<input type="text" jsf:id="dp"/>
<script type="text/javascript">
var dpElm = document.getElementById("form:dp");
dpElm.dataset.datepicker = true;
dpElm.dataset.dateformat = #{someBean.dateformat};
//...
</script>
<div jsf:id="someOtherPanel">
<h1>Bad bad code...</h1>
</div>
Herbstcampus 2015 – JSF meets Javascript 2. ed 29
JSF & JavaScript
• Why Inline-Scripting sucks
• Wartbarkeit?
• DRY & Separation of concerns?
• Fehlersuche?
• Weiche Faktoren
• Auslagerung = Modularisierung
• Performanz + Traffic
Herbstcampus 2015 – JSF meets Javascript 2. ed 30
Enterprise JavaScript
be unobtrusive
use consistent
pattern
use build systems
write tests
minimize globals
Herbstcampus 2015 – JSF meets Javascript 2. ed 31
Enterprise JavaScript
be unobtrusive
use consistent
pattern
use build systems
write tests
minimize globals
Herbstcampus 2015 – JSF meets Javascript 2. ed 32
Enterprise JS: Globals
• Globals are evil!
• Kollisionen
• Libraries
• Andere JS-Dateien
var myglobal = "hello"; // antipattern
console.log(myglobal); // "hello"
console.log(window.myglobal); // "hello"
console.log(window["myglobal"]); // "hello"
console.log(this.myglobal); // "hello"
Herbstcampus 2015 – JSF meets Javascript 2. ed 33
Enterprise JS: Globals
• Namespace pattern
• Module
• Mit Tools (z.B. Browserify)
• ES2015-Modules
//------ myFunc.js ------
export default function () { ... };
//------ main1.js ------
import myFunc from 'myFunc';
myFunc();
var Application = {};
Application.SubModul = {};
Application.SubModul = {
SomeClass : function(){...}
};
Herbstcampus 2015 – JSF meets Javascript 2. ed 34
Enterprise JavaScript
be unobtrusive
use consistent
pattern
use build systems
write tests
minimize globals
Herbstcampus 2015 – JSF meets Javascript 2. ed 35
Enterprise JS: Pattern
• JavaScript === dynamisch
• 1000 Wege führen nach Rom
• Das richtige Pattern finden
• !== Inline-Scripting, !== Globals
• Wohlbefinden des Teams
• „Framework Faktoren“
• Pattern konsistent einsetzen
• Explizit
• Implizit
Herbstcampus 2015 – JSF meets Javascript 2. ed 36
Enterprise JS: Module-Pattern
• Von vielen JS-Bibliotheken verwendet
• Minimiert globale Variablen
• Strukuriert Code
• Information Hiding & Vererbung
• Herzstück
• Self-Invoking Functions
• Function-Scope von JavaScript
SomeNameSpace.Module = (function () {
//...
return PublicApi;
})();
Herbstcampus 2015 – JSF meets Javascript 2. ed 37
Module-Pattern: Klassensimulation
• KlassensimulationSomeNameSpace.DatePicker = (function () {
//constructor
var DatePicker = function(param){
this.param = param;
};
//public method
DatePicker.prototype.init = function(){
//use call to keep this reference
privateMethod.call(this);
};
//private method
var privateMethod = function(){
console.log(this.param);
};
return DatePicker;
})();
//usage
new SomeNameSpace.DatePicker("hello").init(); //prints hello
Herbstcampus 2015 – JSF meets Javascript 2. ed 38
ES 2015: Class-Syntax
class DatePicker extends BaseConent{
constructor(param){
super();
this.param = param;
}
get otherParam(){
return this.otherParam;
}
set otherParam(param){
this.otherParam = param;
}
init(){
this._init();
}
_init(){
console.log(this.param);
}
}
new DatePicker("hello").init();
Herbstcampus 2015 – JSF meets Javascript 2. ed 39
Enterprise JavaScript
be unobtrusive
use consistent
pattern
use build systems
write tests
minimize globals
Herbstcampus 2015 – JSF meets Javascript 2. ed 40
Separation of structure and behavior
Inline-Scripting
Herbstcampus 2015 – JSF meets Javascript 2. ed 41
Separation of structure and behavior
• Problem: JavaScript wo und wie initialisieren?
• Jede Komponente hat eigenes Script-Modul
• Parameter aus JSF (Java) an JS übergeben
Herbstcampus 2015 – JSF meets Javascript 2. ed 42
Separation of structure and behavior
• Problem: JavaScript wo und wie initialisieren?
• Jede Komponente hat eigenes Script-Modul
• Parameter aus JSF (Java) an JS übergeben
<composite:interface>
<composite:attribute name="value" type="java.lang.Date"/>
<composite:attribute name="format" type="java.lang.String"/>
</composite:interface>
<composite:implementation>
<input type="text" jsf:id="dp" jsf:value="#{cc.attrs.value}"/>
<script>
new ok.DatePicker({
clientId: "#{cc.clientId}",
format: "#{cc.attrs.format}"
});
</script>
</composite:implementation>
Herbstcampus 2015 – JSF meets Javascript 2. ed 43
Separation of structure and behavior
• Im Browser...
<input type="text" id="form:component:dp" value="1.1.2015"/>
<script>
new ok.DatePicker({
clientId: "form:component",
format: "dd.mm.yyyy"
});
</script>
Herbstcampus 2015 – JSF meets Javascript 2. ed 44
JS-Initialisierung mit Nicole
Herbstcampus 2015 – JSF meets Javascript 2. ed 45
JS-Initialisierung mit Nicole
• True separation of structure and behavior
<composite:interface>
<composite:attribute name="value" type="java.lang.Date"/>
<composite:attribute name="format" type="java.lang.String"/>
</composite:interface>
<composite:implementation>
<input type="text" jsf:id="dp" jsf:value="#{cc.attrs.value}"/>
<nicole:module modulename="DatePicker">
<nicole:jsparameter name="format" value="#{cc.attrs.format}"/>
</nicole:module>
</composite:implementation>
Herbstcampus 2015 – JSF meets Javascript 2. ed 46
JS-Initialisierung mit Nicole
• Im Browser...
<input id="form:component:dp" value="1.1.2015" type="text"/>
<input id="form:component:nicoleCC:nicole"
type="hidden"
data-modulename="DatePicker"
data-format="dd.mm.yyyy"
data-clientid="form:component"/>
Herbstcampus 2015 – JSF meets Javascript 2. ed 47
JS-Initialisierung mit Nicole
• Und JavaScript:
Nicole.module("DatePicker", function () {
this.$elm("datePicker").datepicker({
dateFormat: this.parameter("format")
});
});
Herbstcampus 2015 – JSF meets Javascript 2. ed 48
Nicole Zusammenfassung
• JSF bleibt JSF
• HTML bleibt HTML
• JavaScript: erzwungenes Pattern
 github.com/dskgry/nicole
Herbstcampus 2015 – JSF meets Javascript 2. ed 49
Enterprise JavaScript
be unobtrusive
use consistent
pattern
use build systems
write tests
minimize globals
Herbstcampus 2015 – JSF meets Javascript 2. ed 50
Enterprise JS: Build & Test
• Build-Systeme
• Concatenation & Minification
• Transpiling
• Linting
• Testing
Herbstcampus 2015 – JSF meets Javascript 2. ed 51
Enterprise JS: Build & Test
• Test: What do we test?
• Toolsets
• Runner
• Assertions%
• Spy/Mock
• CI
• Jenkins Integration
• Statische Codeanalysen
• Coverage
describe("the chartComponent", function () {
it("does not support the type bar", function () {
expect(function(){
new ok.ChartComponent({
clientId: "client:id",
chartType: "bar"
});
}).toThrow();
});
});
Herbstcampus 2015 – JSF meets Javascript 2. ed 52
JSF & JavaScript: JSON-Kommunikation
Herbstcampus 2015 – JSF meets Javascript 2. ed 53
JSF & JavaScript: JSON-Kommunikation
• JSF (Ajax) Kommunikation basiert auf XML
• semantische Daten
• JS-Komponenten nutzen JSON
• Übertragung „reiner“ Daten nötig
<partial-response id="j_id1"><changes><update
id="parentForm"><![CDATA[
<form id="parentForm" method="post" class="container">
<input type="hidden" name="parentForm" value="parentForm" />
Herbstcampus 2015 – JSF meets Javascript 2. ed 54
JSF & JavaScript: JSON-Kommunikation
• Warum nicht mit JAX-RS
• Stateless vs. Stateful
• JSF-Lifecycle
• CDI-Scopes
• Viewscope?
Herbstcampus 2015 – JSF meets Javascript 2. ed 55
JSF & JavaScript: JSON-Kommunikation
• Übertragung des JSON in Hidden-Input-Fields
• Nutzung von FacesConvertern (Java zu JSON konvertieren)
• Nutzung von JSF im Standard
• Minimaler Overhead
Herbstcampus 2015 – JSF meets Javascript 2. ed 56
JSF & JavaScript: JSON-Kommunikation
SomeDataModel
FacesConverter Hidden Input
JavaScript
Herbstcampus 2015 – JSF meets Javascript 2. ed 57
SomeDataModel
FacesConverter Hidden Input
JavaScript
JSF & JavaScript: JSON-Kommunikation
Herbstcampus 2015 – JSF meets Javascript 2. ed 58
JSF & JavaScript: JSON-Kommunikation
• Komponente hat ein geeignetes Datenmodell
• z.B. Chart - Menge aus x und y Werten
• z.B. Map - Menge aus Lat. und. Lon. Werten
public abstract class ChartDataModel<T, X, Y> {
private Map<X, Y> dataSeries;
public Map<X, Y> getDataSeries() {
return dataSeries;
}
protected abstract X getXValue(T t);
protected abstract Y getYValue(T t);
}
Herbstcampus 2015 – JSF meets Javascript 2. ed 59
SomeDataModel
FacesConverter Hidden Input
JavaScript
JSF & JavaScript: JSON-Kommunikation
Herbstcampus 2015 – JSF meets Javascript 2. ed 60
JSF & JavaScript: JSON-Kommunikation
• FacesConverter: Datenmodell  JSON
• JavaEE 7 JSON-API
@FacesConverter(value = "de.openknowledge.ChartConverter")
public class ChartConverter implements Converter {
...
public String getAsString(FacesContext ctx, UIComponent comp,
Object value) {
ChartDataModel dataModel = (ChartDataModel) value;
JsonArrayBuilder dataArray = Json.createArrayBuilder();
...
return dataArray.build().toString();
}
...
Herbstcampus 2015 – JSF meets Javascript 2. ed 61
JSF & JavaScript: JSON-Kommunikation
SomeDataModel
FacesConverter Hidden Input
JavaScript
JSON-parse
Herbstcampus 2015 – JSF meets Javascript 2. ed 62
JSF & JavaScript: JSON-Kommunikation
• Converter am Hidden-Input-Feld registrieren
• Hidden-Input-Field mit JSON „befüllen“
<input
type="hidden"
jsf:id="jsonHelper"
jsf:converter="de.openknowledge.ChartConverter"
jsf:value="#{somebean.chartDataModel}"/>
Herbstcampus 2015 – JSF meets Javascript 2. ed 63
JSF & JavaScript: JSON-Kommunikation
• HTML
• JavaScript, jQuery
<input value="{"xAxes":["04.09.14","06.09.14"],
"yAxes":["8.74","85.77"]}"/>
var chartDataJson =
JSON.parse(this.$elm("jsonHelper").val());
Herbstcampus 2015 – JSF meets Javascript 2. ed 64
JSF & JavaScript: JSON-Kommunikation
• Und andersrum?
Herbstcampus 2015 – JSF meets Javascript 2. ed 65
JSF & JavaScript: JSON-Kommunikation
SomeDataModel
FacesConverter Hidden Input
JavaScript
toObject
JSON.stringify
send via jsf.ajax
Herbstcampus 2015 – JSF meets Javascript 2. ed 66
Herbstcampus 2015 – JSF meets Javascript 2. ed 67
Ausblick
• JSF 2.3: Evolution statt Revolution
• Ajax method invokation
• MVC 1.0
• Auch hier: Chaos vermeiden
• Weg von DOM-Manipulation?
• EcmaScript 2015 / 2016
• class syntax / promises
• privates
Herbstcampus 2015 – JSF meets Javascript 2. ed 68
Fazit
• JSF & JavaScript
 Pattern essentiell
• JSON-Kommunikation
 JavaEE 7 Boardmittel
• Eigene Komponenten bringen enorme Flexibilität
 initialer Aufwand höher
• Einsatz von 3rd-Party Libraries abwägen
 0 8 15 vs. fancy web
Vielen Dank!
Sven Kölpin
open knowledge GmbH

JSF meets JS (2. ed.) - JSF-Komponenten mit JavaScript

  • 1.
    JSF meets JS(2. ed.) JSF-Komponenten mit JavaScript Sven Kölpin open knowledge GmbH
  • 2.
    Herbstcampus 2015 –JSF meets Javascript 2. ed 2 JSF in Webanwendungen?
  • 3.
    Herbstcampus 2015 –JSF meets Javascript 2. ed 3 JavaScript & SPA • Single page application (SPA) • Nur eine HTML-Seite • DOM-Manipulation hintergründig • Business-Logik im Client • Status im Browser • Rolle des Servers • Stateless
  • 4.
    Herbstcampus 2015 –JSF meets Javascript 2. ed 4 JavaScript & SPA • Hypegefahr • „Is angularJs dead?“ • „ReactJs is the next big thing!“ • Architekturelle Probleme • Geschwindigkeit • Browserkompatibilität • Pitfalls • Pionierarbeit (v.a. Enterpriseumfeld)
  • 5.
    Herbstcampus 2015 –JSF meets Javascript 2. ed 5 Serverseitige Webanwendungen • Berüchtigt im Enterprise Umfeld • Bekanntes Programiermodell • Weniger Medienbrüche • Rich Internet Applications • Ajax • Presentations-Logik • Rolle von JavaScript • DOM-Manipulation
  • 6.
    Herbstcampus 2015 –JSF meets Javascript 2. ed 6 Serverseitige Webanwendungen • Berüchtigt im Enterprise Umfeld • Bekanntes Programiermodell • Weniger Medienbrüche • Rich Internet Applications • Ajax • Presentations-Logik • Rolle von JavaScript • DOM-Manipulation  BEST OF BREED
  • 7.
    Herbstcampus 2015 –JSF meets Javascript 2. ed 7 JSF meets JavaScript
  • 8.
    Herbstcampus 2015 –JSF meets Javascript 2. ed 8 JSF meets JS: Why not Primefaces?
  • 9.
    Herbstcampus 2015 –JSF meets Javascript 2. ed 9 JSF meets JS: Why not Primefaces? • Kundenanforderungen an die GUI • Individuelle Probleme • Frameworks sind Blackboxes • Third-Party-Libraries • Boilerplate • Bugs • Abhängigkeiten
  • 10.
    Herbstcampus 2015 –JSF meets Javascript 2. ed 10 Ziele des Vortrags • Best-Practices vermitteln • JavaScript-Pattern • JSF-JS-Komponenten • JSF-JavaScript- Kommunikation → Den Einsatz von 3rd Party Libraries überdenken
  • 11.
    Herbstcampus 2015 –JSF meets Javascript 2. ed 11 Was im Standard geschah...
  • 12.
    Herbstcampus 2015 –JSF meets Javascript 2. ed 12 JSF Composite Components • JSF-Code in Komponenten auslagern • Parametrisierbar • Wiederverwendbar • Ziel: deklarative Kapselung von GUI-Logik <html xmlns="http://www.w3.org/1999/xhtml" xmlns:ok="http://xmlns.jscp.org/jsf/composite/ok"> <ok:labelTextBox value="#{someBean.firstName}" name="Firstname"> </ok:labelTextBox>
  • 13.
    Herbstcampus 2015 –JSF meets Javascript 2. ed 13 JSF Composite Components • „Keep simple things simple“ • XHTML Interface • XHTML Implementierung • „Convention over code & configuration“ • Namenskonventionen • Ressourcenzugriff
  • 14.
    Herbstcampus 2015 –JSF meets Javascript 2. ed 14 Keep simple things simple • Interface & Implementierung <html xmlns="http://www.w3.org/1999/xhtml" xmlns:composite="http://java.sun.com/jsf/composite" xmlns:jsf="http://xmlns.jcp.org/jsf"> <composite:interface> <composite:attribute name="name" /> <composite:attribute name="value"/> </composite:interface> <composite:implementation> <label jsf:id="lbl" jsf:for="inputComponent" jsf:value="#{cc.attrs.name}"/> <input type="text" jsf:id="inputComponent" jsf:value="#{cc.attrs.value}"/> </composite:implementation>
  • 15.
    Herbstcampus 2015 –JSF meets Javascript 2. ed 15 Convention over configuration • webapp/resources/ok/labelTextBox.xhtml  xmlns:ok="http://xmlns.jcp.org/jsf/composite/ok" <html xmlns="http://www.w3.org/1999/xhtml" xmlns:composite="http://java.sun.com/jsf/composite" xmlns:jsf="http://xmlns.jcp.org/jsf"> <composite:interface> <composite:attribute name="name" /> <composite:attribute name="value"/> </composite:interface> <composite:implementation> <label jsf:id="lbl" jsf:for="inputComponent" jsf:value="#{cc.attrs.name}"/> <input type="text" jsf:id="inputComponent" jsf:value="#{cc.attrs.value}"/> </composite:implementation>
  • 16.
    Herbstcampus 2015 –JSF meets Javascript 2. ed 16 Und JavaScript?
  • 17.
    Herbstcampus 2015 –JSF meets Javascript 2. ed 17 JSF und JS: Der Standard • Alles ist deklarativ in JSF (XML-Kapselung) • Komponenten • JavaScript • Standardisierte JavaScript-Integration: Clientbehaviors <h:dataTable value="#{someBean.list}" var="row"> <h:column>#{row.valA}</h:column> <h:column>#{row.valB}</h:column> </h:dataTable> <h:commandButton value="Submit"> <f:ajax execute="@this" render="panelB"/> </h:commandButton>
  • 18.
    Herbstcampus 2015 –JSF meets Javascript 2. ed 18 Client Behaviors • JavaScript deklarativ kapseln • Ähnlich zu <f:ajax/> - Tag • Komponenten um clientseitige Funktionalität erweitern <html xmlns="http://www.w3.org/1999/xhtml" xmlns:okb="http://openknowledge.de/behavior" ...> <input type="submit" jsf:id="submit" value="Submit this"> <okb:confirm message="Are you sure?"/> <f:ajax render="parentForm"/> </input>
  • 19.
    Herbstcampus 2015 –JSF meets Javascript 2. ed 19 Client Behaviors • JavaScript deklarativ kapseln • Ähnlich zu <f:ajax/> - Tag • Komponenten um clientseitige Funktionalität erweitern <html xmlns="http://www.w3.org/1999/xhtml" xmlns:okb="http://openknowledge.de/behavior" ...> <input type="submit" jsf:id="submit" value="Submit this"> <okb:confirm message="Are you sure?"/> <f:ajax render="parentForm"/> </input>
  • 20.
    Herbstcampus 2015 –JSF meets Javascript 2. ed 20 Client Behaviors • Was passiert da? <input id="parentForm:submit" onclick="jsf.util.chain(this,event, 'return confirm('Are you sure?')', 'mojarra.ab(this,event,'action',0,'parentForm')');"/> <input type="submit" jsf:id="submit" value="Submit this"> <okb:confirm message="Are you sure?"/> <f:ajax render="parentForm"/> </input>
  • 21.
    Herbstcampus 2015 –JSF meets Javascript 2. ed 21 Client Behaviors • Was braucht man? • Behavior-Klasse • extends ClientBehaviorBase • @FacesBehavior(“de.my.behavior“) • taglib.xml • Konfiguration  • JavaScript-Code • Das eigentliche Herzstück
  • 22.
    Herbstcampus 2015 –JSF meets Javascript 2. ed 22 Client Behaviors @FacesBehavior("de.openknowledge.SimpleBehavior") public class SimpleBehavior extends ClientBehaviorBase { private String message; @Override public String getScript(ClientBehaviorContext behaviorContext) { return "return confirm('“+getMessage()+“')"; } public String getMessage() { return message; } public void setMessage(String msg) { this.message = msg; } ...
  • 23.
    Herbstcampus 2015 –JSF meets Javascript 2. ed 23 Client Behaviors • JavaScript in Java? @FacesBehavior("de.openknowledge.SimpleBehavior") @ResourceDependencies(value = { @ResourceDependency(name = "ok/confirm.js") }) public class SimpleBehavior extends ClientBehaviorBase { private String message; @Override public String getScript(ClientBehaviorContext behaviorContext) { return "ok.confirmDialog.show();"; } ... }
  • 24.
    Herbstcampus 2015 –JSF meets Javascript 2. ed 24 Client Behaviors • META-INF/ok.taglib.xml <facelet-taglib version="2.2" … > <namespace>http://openknowledge.de/behavior</namespace> <tag> <tag-name>confirm</tag-name> <behavior> <behavior-id> de.openknowledge.SimpleBehavior </behavior-id> </behavior> <attribute> <name>message</name> </attribute> </tag> ...
  • 25.
    Herbstcampus 2015 –JSF meets Javascript 2. ed 25 Client Behaviors • Zeitgemäß? • Konfiguration  • Boilerplate  • Eventbasiert  • Keine zwingenden JS-Pattern
  • 26.
    Herbstcampus 2015 –JSF meets Javascript 2. ed 26 JSF & JavaScript – Ein Chaos vermeiden
  • 27.
    Herbstcampus 2015 –JSF meets Javascript 2. ed 27 JSF & JavaScript • Umittelbare Integration von JavaScript in JSF • Nicht standardisiert • Inline Scripting <input type="text" jsf:id="dp"/> <script type="text/javascript"> var dpElm = document.getElementById("form:dp"); dpElm.dataset.datepicker = true; dpElm.dataset.dateformat = #{someBean.dateformat}; //... </script> <div jsf:id="someOtherPanel"> <h1>Bad bad code...</h1> </div>
  • 28.
    Herbstcampus 2015 –JSF meets Javascript 2. ed 28 JSF & JavaScript • Umittelbare Integration von JavaScript in JSF • Nicht standardisiert • Inline Scripting <input type="text" jsf:id="dp"/> <script type="text/javascript"> var dpElm = document.getElementById("form:dp"); dpElm.dataset.datepicker = true; dpElm.dataset.dateformat = #{someBean.dateformat}; //... </script> <div jsf:id="someOtherPanel"> <h1>Bad bad code...</h1> </div>
  • 29.
    Herbstcampus 2015 –JSF meets Javascript 2. ed 29 JSF & JavaScript • Why Inline-Scripting sucks • Wartbarkeit? • DRY & Separation of concerns? • Fehlersuche? • Weiche Faktoren • Auslagerung = Modularisierung • Performanz + Traffic
  • 30.
    Herbstcampus 2015 –JSF meets Javascript 2. ed 30 Enterprise JavaScript be unobtrusive use consistent pattern use build systems write tests minimize globals
  • 31.
    Herbstcampus 2015 –JSF meets Javascript 2. ed 31 Enterprise JavaScript be unobtrusive use consistent pattern use build systems write tests minimize globals
  • 32.
    Herbstcampus 2015 –JSF meets Javascript 2. ed 32 Enterprise JS: Globals • Globals are evil! • Kollisionen • Libraries • Andere JS-Dateien var myglobal = "hello"; // antipattern console.log(myglobal); // "hello" console.log(window.myglobal); // "hello" console.log(window["myglobal"]); // "hello" console.log(this.myglobal); // "hello"
  • 33.
    Herbstcampus 2015 –JSF meets Javascript 2. ed 33 Enterprise JS: Globals • Namespace pattern • Module • Mit Tools (z.B. Browserify) • ES2015-Modules //------ myFunc.js ------ export default function () { ... }; //------ main1.js ------ import myFunc from 'myFunc'; myFunc(); var Application = {}; Application.SubModul = {}; Application.SubModul = { SomeClass : function(){...} };
  • 34.
    Herbstcampus 2015 –JSF meets Javascript 2. ed 34 Enterprise JavaScript be unobtrusive use consistent pattern use build systems write tests minimize globals
  • 35.
    Herbstcampus 2015 –JSF meets Javascript 2. ed 35 Enterprise JS: Pattern • JavaScript === dynamisch • 1000 Wege führen nach Rom • Das richtige Pattern finden • !== Inline-Scripting, !== Globals • Wohlbefinden des Teams • „Framework Faktoren“ • Pattern konsistent einsetzen • Explizit • Implizit
  • 36.
    Herbstcampus 2015 –JSF meets Javascript 2. ed 36 Enterprise JS: Module-Pattern • Von vielen JS-Bibliotheken verwendet • Minimiert globale Variablen • Strukuriert Code • Information Hiding & Vererbung • Herzstück • Self-Invoking Functions • Function-Scope von JavaScript SomeNameSpace.Module = (function () { //... return PublicApi; })();
  • 37.
    Herbstcampus 2015 –JSF meets Javascript 2. ed 37 Module-Pattern: Klassensimulation • KlassensimulationSomeNameSpace.DatePicker = (function () { //constructor var DatePicker = function(param){ this.param = param; }; //public method DatePicker.prototype.init = function(){ //use call to keep this reference privateMethod.call(this); }; //private method var privateMethod = function(){ console.log(this.param); }; return DatePicker; })(); //usage new SomeNameSpace.DatePicker("hello").init(); //prints hello
  • 38.
    Herbstcampus 2015 –JSF meets Javascript 2. ed 38 ES 2015: Class-Syntax class DatePicker extends BaseConent{ constructor(param){ super(); this.param = param; } get otherParam(){ return this.otherParam; } set otherParam(param){ this.otherParam = param; } init(){ this._init(); } _init(){ console.log(this.param); } } new DatePicker("hello").init();
  • 39.
    Herbstcampus 2015 –JSF meets Javascript 2. ed 39 Enterprise JavaScript be unobtrusive use consistent pattern use build systems write tests minimize globals
  • 40.
    Herbstcampus 2015 –JSF meets Javascript 2. ed 40 Separation of structure and behavior Inline-Scripting
  • 41.
    Herbstcampus 2015 –JSF meets Javascript 2. ed 41 Separation of structure and behavior • Problem: JavaScript wo und wie initialisieren? • Jede Komponente hat eigenes Script-Modul • Parameter aus JSF (Java) an JS übergeben
  • 42.
    Herbstcampus 2015 –JSF meets Javascript 2. ed 42 Separation of structure and behavior • Problem: JavaScript wo und wie initialisieren? • Jede Komponente hat eigenes Script-Modul • Parameter aus JSF (Java) an JS übergeben <composite:interface> <composite:attribute name="value" type="java.lang.Date"/> <composite:attribute name="format" type="java.lang.String"/> </composite:interface> <composite:implementation> <input type="text" jsf:id="dp" jsf:value="#{cc.attrs.value}"/> <script> new ok.DatePicker({ clientId: "#{cc.clientId}", format: "#{cc.attrs.format}" }); </script> </composite:implementation>
  • 43.
    Herbstcampus 2015 –JSF meets Javascript 2. ed 43 Separation of structure and behavior • Im Browser... <input type="text" id="form:component:dp" value="1.1.2015"/> <script> new ok.DatePicker({ clientId: "form:component", format: "dd.mm.yyyy" }); </script>
  • 44.
    Herbstcampus 2015 –JSF meets Javascript 2. ed 44 JS-Initialisierung mit Nicole
  • 45.
    Herbstcampus 2015 –JSF meets Javascript 2. ed 45 JS-Initialisierung mit Nicole • True separation of structure and behavior <composite:interface> <composite:attribute name="value" type="java.lang.Date"/> <composite:attribute name="format" type="java.lang.String"/> </composite:interface> <composite:implementation> <input type="text" jsf:id="dp" jsf:value="#{cc.attrs.value}"/> <nicole:module modulename="DatePicker"> <nicole:jsparameter name="format" value="#{cc.attrs.format}"/> </nicole:module> </composite:implementation>
  • 46.
    Herbstcampus 2015 –JSF meets Javascript 2. ed 46 JS-Initialisierung mit Nicole • Im Browser... <input id="form:component:dp" value="1.1.2015" type="text"/> <input id="form:component:nicoleCC:nicole" type="hidden" data-modulename="DatePicker" data-format="dd.mm.yyyy" data-clientid="form:component"/>
  • 47.
    Herbstcampus 2015 –JSF meets Javascript 2. ed 47 JS-Initialisierung mit Nicole • Und JavaScript: Nicole.module("DatePicker", function () { this.$elm("datePicker").datepicker({ dateFormat: this.parameter("format") }); });
  • 48.
    Herbstcampus 2015 –JSF meets Javascript 2. ed 48 Nicole Zusammenfassung • JSF bleibt JSF • HTML bleibt HTML • JavaScript: erzwungenes Pattern  github.com/dskgry/nicole
  • 49.
    Herbstcampus 2015 –JSF meets Javascript 2. ed 49 Enterprise JavaScript be unobtrusive use consistent pattern use build systems write tests minimize globals
  • 50.
    Herbstcampus 2015 –JSF meets Javascript 2. ed 50 Enterprise JS: Build & Test • Build-Systeme • Concatenation & Minification • Transpiling • Linting • Testing
  • 51.
    Herbstcampus 2015 –JSF meets Javascript 2. ed 51 Enterprise JS: Build & Test • Test: What do we test? • Toolsets • Runner • Assertions% • Spy/Mock • CI • Jenkins Integration • Statische Codeanalysen • Coverage describe("the chartComponent", function () { it("does not support the type bar", function () { expect(function(){ new ok.ChartComponent({ clientId: "client:id", chartType: "bar" }); }).toThrow(); }); });
  • 52.
    Herbstcampus 2015 –JSF meets Javascript 2. ed 52 JSF & JavaScript: JSON-Kommunikation
  • 53.
    Herbstcampus 2015 –JSF meets Javascript 2. ed 53 JSF & JavaScript: JSON-Kommunikation • JSF (Ajax) Kommunikation basiert auf XML • semantische Daten • JS-Komponenten nutzen JSON • Übertragung „reiner“ Daten nötig <partial-response id="j_id1"><changes><update id="parentForm"><![CDATA[ <form id="parentForm" method="post" class="container"> <input type="hidden" name="parentForm" value="parentForm" />
  • 54.
    Herbstcampus 2015 –JSF meets Javascript 2. ed 54 JSF & JavaScript: JSON-Kommunikation • Warum nicht mit JAX-RS • Stateless vs. Stateful • JSF-Lifecycle • CDI-Scopes • Viewscope?
  • 55.
    Herbstcampus 2015 –JSF meets Javascript 2. ed 55 JSF & JavaScript: JSON-Kommunikation • Übertragung des JSON in Hidden-Input-Fields • Nutzung von FacesConvertern (Java zu JSON konvertieren) • Nutzung von JSF im Standard • Minimaler Overhead
  • 56.
    Herbstcampus 2015 –JSF meets Javascript 2. ed 56 JSF & JavaScript: JSON-Kommunikation SomeDataModel FacesConverter Hidden Input JavaScript
  • 57.
    Herbstcampus 2015 –JSF meets Javascript 2. ed 57 SomeDataModel FacesConverter Hidden Input JavaScript JSF & JavaScript: JSON-Kommunikation
  • 58.
    Herbstcampus 2015 –JSF meets Javascript 2. ed 58 JSF & JavaScript: JSON-Kommunikation • Komponente hat ein geeignetes Datenmodell • z.B. Chart - Menge aus x und y Werten • z.B. Map - Menge aus Lat. und. Lon. Werten public abstract class ChartDataModel<T, X, Y> { private Map<X, Y> dataSeries; public Map<X, Y> getDataSeries() { return dataSeries; } protected abstract X getXValue(T t); protected abstract Y getYValue(T t); }
  • 59.
    Herbstcampus 2015 –JSF meets Javascript 2. ed 59 SomeDataModel FacesConverter Hidden Input JavaScript JSF & JavaScript: JSON-Kommunikation
  • 60.
    Herbstcampus 2015 –JSF meets Javascript 2. ed 60 JSF & JavaScript: JSON-Kommunikation • FacesConverter: Datenmodell  JSON • JavaEE 7 JSON-API @FacesConverter(value = "de.openknowledge.ChartConverter") public class ChartConverter implements Converter { ... public String getAsString(FacesContext ctx, UIComponent comp, Object value) { ChartDataModel dataModel = (ChartDataModel) value; JsonArrayBuilder dataArray = Json.createArrayBuilder(); ... return dataArray.build().toString(); } ...
  • 61.
    Herbstcampus 2015 –JSF meets Javascript 2. ed 61 JSF & JavaScript: JSON-Kommunikation SomeDataModel FacesConverter Hidden Input JavaScript JSON-parse
  • 62.
    Herbstcampus 2015 –JSF meets Javascript 2. ed 62 JSF & JavaScript: JSON-Kommunikation • Converter am Hidden-Input-Feld registrieren • Hidden-Input-Field mit JSON „befüllen“ <input type="hidden" jsf:id="jsonHelper" jsf:converter="de.openknowledge.ChartConverter" jsf:value="#{somebean.chartDataModel}"/>
  • 63.
    Herbstcampus 2015 –JSF meets Javascript 2. ed 63 JSF & JavaScript: JSON-Kommunikation • HTML • JavaScript, jQuery <input value="{"xAxes":["04.09.14","06.09.14"], "yAxes":["8.74","85.77"]}"/> var chartDataJson = JSON.parse(this.$elm("jsonHelper").val());
  • 64.
    Herbstcampus 2015 –JSF meets Javascript 2. ed 64 JSF & JavaScript: JSON-Kommunikation • Und andersrum?
  • 65.
    Herbstcampus 2015 –JSF meets Javascript 2. ed 65 JSF & JavaScript: JSON-Kommunikation SomeDataModel FacesConverter Hidden Input JavaScript toObject JSON.stringify send via jsf.ajax
  • 66.
    Herbstcampus 2015 –JSF meets Javascript 2. ed 66
  • 67.
    Herbstcampus 2015 –JSF meets Javascript 2. ed 67 Ausblick • JSF 2.3: Evolution statt Revolution • Ajax method invokation • MVC 1.0 • Auch hier: Chaos vermeiden • Weg von DOM-Manipulation? • EcmaScript 2015 / 2016 • class syntax / promises • privates
  • 68.
    Herbstcampus 2015 –JSF meets Javascript 2. ed 68 Fazit • JSF & JavaScript  Pattern essentiell • JSON-Kommunikation  JavaEE 7 Boardmittel • Eigene Komponenten bringen enorme Flexibilität  initialer Aufwand höher • Einsatz von 3rd-Party Libraries abwägen  0 8 15 vs. fancy web
  • 69.