Marcus Fihlon

­čĹĘÔÇŹ­čĺ╝ Scrum Master | ­čĹĘÔÇŹ­čĆź Agile Coach | ­čžĹÔÇŹ­čĺ╗ Software Craftsman

Von 2016 bis 2018 durfte ich drei Jahre in Folge mit einem Vortrag beim Java Forum Stuttgart zu Gast sein. 2019 passte es leider zeitlich nicht und dann kam Corona. Mittlerweile haben wir alle mehr oder weniger gut die Pandemie ├╝berstanden und ich bin wieder heiss auf Konferenzen!

Zwar habe ich f├╝r dieses Jahr keine Vortr├Ąge vorbereitet, aber ich werde trotzdem beim Java Forum Stuttgart dabei sein. Es ist eine coole Konferenz mit tollen Vortr├Ągen und wieder eine super M├Âglichkeit, bekannte Gesichter zu treffen und auch wieder neue interessante Personen kennenzulernen.

Ihr findet mich haupts├Ąchlich beim Stand des iJUG. Dort wird es auch dieses Jahr wieder einige Ausgaben unseres Community-Magazins Java aktuell geben. Dort bin ich Teil des Redaktionsbeirats. Wir sind immer auf der Suche nach Autoren, die auch mal einen eigenen Beitrag in einem professionellen Fachmagazin ver├Âffentlichen m├Âchten. Falls dich das reizt, sprich mich gerne an. Es ist wirklich viel weniger schwierig, als viele denken!

Aber zur├╝ck zum Java Forum Stuttgart. Oder besser erstmal hin. Also hinkommen. Zum JFS bin ich bisher immer mit dem Zug angereist. In Stuttgart selbst war ich auf meiner Deutschlandreise 2020 auch schon mit meinem Gravelbike. Dieses Jahr habe ich beschlossen, sowohl den Hin- als auch den R├╝ckweg zum JFS mit meinem neuen Reiserad in Angriff zu nehmen.

Meinen Job bei der CSS habe ich auf Ende Juli gek├╝ndigt um im Anschluss drei Monate auf Reisen zu gehen. Dabei habe ich noch einige Ferientage ├╝brig, so dass mein letzter Arbeitstag bereits am 29. Juni sein wird. Das heisst, ich habe schon den ganzen Juli ebenfalls frei und somit genug Zeit f├╝r die kleine Velotour. Falls dich das auch interessiert, kann ich dir meinen Bikepacking Blog empfehlen. Dort habe ich vergangenes Wochenende einen Artikel ├╝ber meine Routenplanung zum Java Forum Stuttgart geschrieben.

Falls du auch beim JFS sein wirst, freue ich mich ├╝ber einen Besuch von dir beim iJUG-Stand. Sage einfach mal Hallo und hole dir eine Gratis-Ausgabe der Java aktuell ab.

Dein Marcus

Web Components sind ein Standard, der komponentenbasierte Softwareentwicklung f├╝r das Web erm├Âglicht. Das folgende Tutorial zeigt, wie man mittels Web Components und Polymer wiederverwendbare Komponenten entwickelt, die in sich gekapselt sind, die sich kombinieren und erweitern lassen.

Web Components sind HTML Standard

Die Zeiten, zu denen man als Java-Entwickler auch ausschliesslich Java-Technologien f├╝r Benutzeroberfl├Ąchen eingesetzt hat, sind schon lange vorbei. ├ťber die Jahre hinweg hat HTML immer mehr Einzug gehalten und kann nun als fester Bestandteil des Java-├ľkosystems betrachtet werden.

Doch HTML ist nicht gleich HTML ÔÇö seit der ersten Version, die vor nunmehr 25 Jahren erschien, hat sich sehr viel getan.Eher still und leise hat sich ein Standard f├╝r ÔÇťWeb ComponentsÔÇŁ fast schon eingeschlichen, welcher aus vier verschiedenen Spezifikationen besteht.

Dieser Standard spezifiziert, wie wiederverwendbare Widgets und Komponenten f├╝r Web-Dokumente und Web-Applikationen erstellt und genutzt werden k├Ânnen. Die Idee dahinter ist, die komponentenbasierte Softwareentwicklung in das World Wide Web zu bringen. Das Komponentenmodell erlaubt die Kapselung von HTML Elementen und deren Interoperabilit├Ąt.

Von vielen Web-Entwicklern nicht beachtet, bieten Web Components enormes Potential, um auf einfache und schnelle Weise moderne und modulare Benutzeroberfl├Ąchen mit HTML zu erstellen.

B├╝cherwurm

Im Folgenden entwickeln wir gemeinsam eine kleine Web-Applikation auf Basis von Web Components und dem Polymer Framework. Wir werden dabei sowohl bereits vorhandene Komponenten einsetzen als auch eigene Komponenten entwickeln. Der Business-Case ist sehr simpel: Mittels eines Eingabefeldes soll eine Buchsuche durchgef├╝hrt und die Resultate ├╝bersichtlich dargestellt werden. Doch was sich so simpel anh├Ârt, hat es durchaus in sich: Wir teilen die Funktionalit├Ąten auf einzelne Komponenten auf, die miteinander interagieren werden.

Projekt Setup

Zuerst m├╝ssen wir unser Projekt einrichten. Wir beginnen mit einem leeren Verzeichnis mit dem Namen bookworm.

Um uns das Management externer Abh├Ąngigkeiten in unserem Projekt einfacher zu machen, nutzen wir Bower. Nach der Installation von Bower initialisieren wir unser Projekt im Projektverzeichnis:

bower init

Alle Fragen k├Ânnen mit dem Standardwert quittiert werden. Nach einer abschliessenden Sicherheitsfrage wird automatisch die neue Datei bower.json angelegt.

Abbildung 1: Verzeichnisstruktur der fertigen Anwendung

Fremdkomponenten einbinden

Im weiteren Verlauf dises Tutorials nutzen wir einige Komponenten aus dem Polymer Project, die wir jetzt einbinden. Eine genaue Erl├Ąuterung der einzelnen Komponenten folgt sp├Ąter.

bower install --save Polymer/polymer PolymerElements/iron-ajax PolymerElements/paper-card PolymerElements/paper-input PolymerElements/paper-material PolymerElements/paper-styles

Es wird automatisch ein neues Verzeichnis mit dem Namen bower_components angelegt und zus├Ątzlich zu unseren gew├╝nschten Komponenten werden noch etliche Abh├Ąngigkeiten heruntergeladen. Alles landet in diesem neuen Verzeichnis, es ist also wunderbar von unserem eigenen Quelltext separiert.

Bevor wir mit der eigentlichen Entwicklung starten k├Ânnen, fehlt uns noch ein Browser und ein Editor. Die Wahl des Browsers ist an dieser Stelle sehr wichtig, denn einige Browser ben├Âtigen zum Testen von Web Components eine HTTP-Verbindung. W├Ąhrend der Safari auch mit Web Components ├╝ber file:// URLs keinerlei Probleme hat, funktionieren Web Components im Chrome ausschliesslich ├╝ber eine HTTP(S) Verbindung. Daher empfiehlt sich der Einsatz eines lokalen Webservers oder eines Editors, der einen integrierten Webserver mitbringt, beispielsweise den kostenlosen Editor Atom mit dem Live Server Package.

Unsere erste eigene Komponente

Unsere kleine App realisieren wir als Komponente, damit sie einfach und schnell auf jeder Webseite eingebunden werden kann. F├╝r unsere eigenen Komponenten erstellen wir im Projektverzeichnis das Unterverzeichnis bookworm_components, dort sammeln wir alle unsere eigenen Komponenten f├╝r diese Anwendung.

Es hat sich als best practice eingeb├╝rgert, f├╝r jede Komponente ein eigenes Verzeichnis zu erstellen und dort alle Dateien dieser Komponente abzulegen. Das Verzeichnis sollte den Namen der Komponente tragen. F├╝r jede Komponente wird uns ein Tag zur Verf├╝gung gestellt, mit dem wir die Komponente im HTML Quelltext einbauen k├Ânnen. Daf├╝r wird der Name der Komponente genutzt, der zwingend einen Bindestrich enthalten muss. Da normale Tags keinen Bindestrich enthalten, kann der Browser so erkennen, dass es sich um eine Komponente handelt. Unsere erste Komponente heisst bookworm-search, also erstellen wir im soeben erzeugten Verzeichnis noch das Unterverzeichnis bookworm-search. Darin legen wir eine leere Datei mit dem Namen bookworm-search.html an. Das ist noch so ein best practice: Die Hauptdatei der Komponente heisst wie die Komponente selbst. Beim sp├Ąteren Import von Komponenten erleichtert uns diese Konvention in der Benennung von Verzeichnissen und Dateien, die richtige Datei f├╝r den Import zu finden.

In der soeben erstellten HTML Datei beginnen wir nun nicht mit der ├╝blichen HTML5 Struktur, denn wir erstellen keine Webseite, sondern eine Komponente. Mit dem Tag <dom-module> definieren wir unsere Komponente und vergeben eine id, die unsere Komponente benennt und auch als Tag f├╝r unsere Komponente fungiert:

<dom-module id="bookworm-search">

Nun erstellen wir den Inhalt unserer Komponente. Der Einfachheit halber benutzen wir erstmal einen statischen Text. Dazu f├╝gen wir innerhalb des <dom-module> Tag ein <template> Tag ein:

<template>
  It works!
</template>

Bevor wir unsere Komponente nutzen k├Ânnen, m├╝ssen wir sie noch bei Polymer registrieren. Dazu sind zwei Schritte notwendig. Zuerst m├╝ssen wir Polymer importieren, damit es uns zur Verf├╝gung steht. Anschliessend k├Ânnen wir unsere Komponente mit JavaScript registrieren lassen. Bei einer Komponente geh├Ârt der Import, ├Ąhnlich einer Java Klasse, an den Anfang. F├╝gen wir nun also folgenden Import ganz am Anfang unserer Datei vor dem <dom-module> Tag hinzu:

<link rel="import" href="../../bower_components/polymer/polymer.html" />

Beachte dabei den Pfad: Bei Imports ist immer die Position der aktuellen Komponente ausschlaggebend, nicht die der Webseite, in der unsere Komponente verwendet wird. Daher m├╝ssen wir erst zwei Verzeichnisebenen zur├╝ck! Nun erg├Ąnzen wir die Registrierung unserer Komponente bei Polymer. Wir ├╝bergeben dabei den Tag f├╝r unsere Komponente und Polymer k├╝mmert sich darum, den Tag und unsere Komponente dem Browser bekannt zu machen. Dieser Code-Schnipsel geh├Ârt zwischen das schliessende </template> und das schliessende </dom-module> Tag:

<script>
  Polymer({
    is: "bookworm-search"
  });
</script>

Herzlichen Gl├╝ckwunsch, mit nur 11 Zeilen Code haben wir unsere allererste eigene Komponente aus Basis von Web Components und Polymer entwickelt!

Unsere Komponente einbauen

Jetzt w├Ąre es toll, wenn wir unsere erste eigene Komponente in Aktion sehen k├Ânnten. Nichts leichter als das, im Projektverzeichnis erstellen wir ein einfaches HTML5 Dokument mit dem Dateinamen index.html und folgendem Inhalt:

<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="UTF-8" />
    <title>Bookworm</title>
  </head>
  <body>
  </body>
</html>

Soweit handelt es sich um ein klassisches HTML5 Grundger├╝st. Wenn wir nun Web Components nutzen m├Âchten, ergibt sich ein kleines Problem: Dieser Stanbdard wird noch nicht von jedem Browser vollumf├Ąnglich unterst├╝tzt (Chrome und Opera unterst├╝tzen diesen Standard in aktuellen Versionen komplett, alle anderen nur teilweise). Doch daf├╝r gibt es eine einfache L├Âsung: Ein Polyfill ist ein in JavaScript geschriebener Code-Baustein, der in Browsern noch nicht unterst├╝tzte Funktionen mittels eines Workarounds nachr├╝stet. Einen solchen Polyfill f├╝r Web Components binden wir nun im <head> Bereich ein:

<script src="bower_components/webcomponentsjs/webcomponents.min.js"></script>

Nun k├Ânnen wir damit starten, unsere Komponente einzubauen. Zuerst m├╝ssen wir unsere Komponente importieren, Damit der Browser sie kennt. Den Import f├╝gen wir im <head> Bereich hinzu:

<link rel="import" href="bookworm_components/bookworm-search/bookworm-search.html" />

Einer Nutzung unserer Komponente steht nun nichts mehr im Weg, wir binden sie einfach mittels ihres eigenen Tags im <body> Bereich ein:

<bookworm-search></bookworm-search>

Fertig! Rufen wir nun unsere Webseite auf und schauen uns das Ergebnis an: It works!

Beim Parsen unserer Webseite st├Âsst der Browser auf den Import unserer Komponente. ├ähnlich einem Stylesheet wird unsere Komponente nachgeladen und bringt dem Browser unser Tag <bookworm-search> bei. Sp├Ąter st├Âsst der Browser dann auf unser Tag und f├╝gt an dieser Stelle unsere Komponente ein, welche nichts anderes macht als It works! auszugeben. So einfach funktionieren Web Components mit PolymerÔÇŽ

Ein Eingabefeld in h├╝bsch

Auch wenn wir auf unseren statischen Text stolz sein k├Ânnen, schaut unser heutiges Ziel etwas anders aus. Wir ben├Âtigen ein Eingabefeld. Da wir den Umgang mit Komponenten lernen m├Âchten, nutzen wir nicht das HTML Input Element, sondern eine Komponente! In diesem Fall eine von Polymer, welche dem Material Design entspricht und etwas h├╝bscher ausschaut. Diese Komponente heisst paper-input und wir haben sie bereits am Anfang des Tutorials heruntergeladen.

Erweitern wir also nun unsere eigene Komponente bookworm-search um die Fremdkomponente paper-input, indem wir diese importieren. F├╝gen wir unserer Komponente einen zweiten Import hinzu:

<link rel="import" href="../../bower_components/paper-input/paper-input.html" />

Nun kennt der Browser diese Fremdkomponente und wir k├Ânnen unseren statischen Text durch das neue Eingabefeld ersetzen:

<paper-input label="enter a search term"></paper-input>

Diese zwei Schritte reichen schon aus. Nach dem Import und dem Einbau des Tags funktioniert diese Komponente schon. Schauen wir uns die Anzeige in einem Browser an:

Abbildung 2: Das neue Eingabefeld im Browser

Wenn wir nun mit der Maus in das Eingabefeld klicken, sehen wir eine Animation. Wenn wir mit der Eingabe beginnen, eine weitere. Diese sind Bestandteil der neuen Komponente, die wir bei uns eingebunden haben.

Databinding

Damit wir sp├Ąter eine Suche mit dem eingegebenen Begriff durchf├╝hren k├Ânnen, m├╝ssen wir an den Wert des Eingabefeldes gelangen. Das ist mittels Databinding von Polymer ziemlich einfach. mWir m├╝ssen das Eingabefeld nur bitten, den Wert in eine Variable zu schreiben. Dazu geben wir den Variablennamen in doppelten geschweiften Klammern im value Attribut an:

<paper-input label="enter a search term" value="{{searchterm}}"></paper-input>

Damit wir ├╝berpr├╝fen k├Ânnen, ob das Databinding funktioniert, k├Ânnen wir den Inhalt der Variable ausgeben lassen. Dazu k├Ânnen wir die Variable innerhalb des Templates angeben, wieder mit doppelten geschweiften Klammern:

{{searchterm}}

Wenn wir nun in das Eingabefeld tippen, erscheint der Suchtext auch darunter als Ausgabe:

Nachdem wir das Databinding ├╝berpr├╝ft haben, k├Ânnen wir die testweise Ausgabe des Suchbegriffes entfernen.

AJAX mal einfach

Nun m├Âchten wir eine Buchsuche per AJAX durchf├╝hren. Gl├╝cklicherweise m├╝ssen wir uns nicht mehr selbst mit dem XMLHttpRequest herumschlagen, das nimmt uns die Komponente iron-ajax ab, welche wir bereits am Anfang des Tutorials heruntergalden haben. F├╝gen wir den entsprechenden Import hinzu:

<link rel="import" href="../../bower_components/iron-ajax/iron-ajax.html" />

Bauen wir nun die AJAX-Komponente ein und verwenden in der URL an der richtigen Stelle einfach unsere Variable f├╝r das Databinding mit dem Eingabefeld:

<iron-ajax url="https://www.googleapis.com/books/v1/volumes?q={{searchterm}}"></iron-ajax>

Wenn wir jetzt etwas in das Eingabefeld tippen, wird es von der paper-input Komponente in die Variable searchterm geschrieben. Da sich die Variable ├Ąndert, aktualisiert Polymer automatisch die URL der iron-ajax Komponente. Wir k├Ânnen nun die AJAX-Komponente bitten, bei jeder ├änderung der URL automatisch einen AJAX-Request abzusetzen. Dazu erg├Ąnzen wir einfach den Parameter auto:

<iron-ajax auto url="https://www.googleapis.com/books/v1/volumes?q={{searchterm}}"></iron-ajax>

Wenn wir unsere Webseite im Browser neu laden und jetzt etwas in das Eingabefeld eintippen, dann k├Ânnen wir in der Netzwerkansicht unseres Browsers sehen, dass nach jedem Tastendruck ein neuer Request abgeschickt wird:

Abbildung 3: Jeder Tastendruck l├Âst einen Request aus

Damit wir die Antwort auf unseren Request sp├Ąter weiterverarbeiten k├Ânnen, m├╝ssen wir diese Antwort speichern. Dazu geben wir an, in welchem Format wir die Antwort erwarten und dass wir den Inhalt der letzten (aktuellsten) Antwort in einer Variablen speichern m├Âchten. Dazu erg├Ąnzen wir im <iron-ajax> Tag folgende zwei Attribute:

handle-as="json"
last-response="{{searchresult}}"

Mittels handle-as teilen wir mit, dass wir eine Antwort im JSON Format erwarten und mittels last-response und Databinding lassen wir uns die letzte Antwort in die Variable searchresult schreiben. So einfach k├Ânnen wir einen AJAX-Request durchf├╝hren!

Verschachtelte Templates

Die Suchergebnisse warten jetzt darauf, angezeigt zu werden. Hierzu kombinieren wir das Databindung von Polymer mit einem weiteren Template, dass die Daten eines Buches anzeigt und so oft wiederholt eingebunden wird, wie es B├╝cher im Suchergebnis gibt. Innerhalb des Templates unserer Komponente f├╝gen wir dazu folgendes neue Template hinzu:

<template is="dom-repeat"
          items="{{searchresult}}">
  <p>{{item.volumeInfo.title}}</p>
</template>

Das Attribut is mit dem Wert dom-repeat sorgt daf├╝r, dass das Template selbst so oft eingebunden wird, wie es Eintr├Ąge in dem Array gibt, das dem Attribut items zugewiesen wurde. Der jeweilige Eintrag aus dem Array steht automatisch in der Variable item zur Verf├╝gung. Zum Test geben wir innerhalb des Templates den Titel des Buches aus. Wenn wir nun einen Test im Browser durchf├╝hren, sollte es wie in diesem Screenshot aussehen:

Abbildung 4: Unsere Suchergebnisse werden angezeigt

Interoperabilit├Ąt

Innerhalb unserer eigenen Komponente k├Ânnten wir nun in der inneren Schleife die Ausgabe der Suchergebnisse vervollst├Ąndigen und w├Ąren fertig. Doch das w├Ąre zu einfach ÔÇö und um die Interoperabilit├Ąt zwischen eigenen Komponenten zu demonstrieren, brauchen wir mindestens zwei eigene Komponenten. Daher lagern wir die Anzeige eines Suchergebnisses in eine eigene Komponente aus. Daraus ergibt sich die interessante Frage, wie nun die Daten eines Buches von der einen Komponente in die andere gelangen, um dort angezeigt zu werden. Doch dazu sp├Ąter mehr, wir beginnen ein paar Schritte vorher und legen erst eine neue Komponente an.

Die neue Komponente soll bookworm-detail heissen. Entsprechend legen wir im Verzeichnis bookworm_components das Unterverzeichnis bookworm-detail an und darin eine neue Datei mit dem Namen bookworm-detail.html. Das Grundger├╝st unserer neuen Komponente entspricht dem Grundger├╝st unserer ersten Komponente:

<link rel="import" href="../../bower_components/polymer/polymer.html" />
<dom-module id="bookworm-detail">
  <template>
  </template>
  <script>
    Polymer({
      is: "bookworm-detail"
    });
  </script>
</dom-module>

Alle Komponenten haben in etwa das gleiche Grundger├╝st. Unserer zweite Komponente, die die Details eines Buches anzeigen soll, m├╝ssen wir die Daten eines Buches ├╝bergeben k├Ânnen. Dazu erweitern wir den JavaScript Code am Ende der Komponente um ein Properties-Objekt:

<script>
  Polymer({
    is: "bookworm-detail",
    properties: {
      bookdata: {
        type: Object
      }
    }
  });
</script>

Innerhalb des Properties-Objekts definieren wir ein bookdata Objekt vom JavaScript-Typ Object. Die Properties-Objekte werden ├╝ber die Attribute des Tags unserer Komponente gesetzt, so k├Ânnen wir die Daten eines Buches von einer Komponente an die n├Ąchste ├╝bergeben. Bevor wir unsere neue Komponente einbauen, erg├Ąnzen wir die Ausgabe des Buchtitels im Template:

<template>
  <p>{{bookdata.volumeInfo.title}}</p>
</template>

Wir k├Ânnen auf unser definiertes Property zugreifen wie auf eine Variable. Bauen wir nun unsere zweite Komponente in die erste Komponente ein. Dazu m├╝ssen wir in der Datei bookworm-search.html einen Import hinzuf├╝gen:

<link rel="import" href="../bookworm-detail/bookworm-detail.html" />

Dabei m├╝ssen wir beachten, dass wir, um zur Komponente bookworm-detail zu gelangen, nur eine Verzeichnisebene nach oben wechseln m├╝ssen. Ersetzen wir nun die direkte Ausgabe des Buchtitels durch den Einbau unserer neuen Komponente und ├╝bergeben dabei gleich die Daten des Buches:

<bookworm-detail bookdata="{{item}}"><bookworm-detail>

Wenn wir uns das Ganze nun erneut im Browser anschauen, sollte es immer noch ausschauen, wie im vorherigen Screenshot, jedoch haben wir technisch gesehen eine sch├Ânere Kapselung erreicht.

Material Design

Wenn wir genau hinschauen, entspricht unsere Applikation noch nicht den Regeln f├╝r Material Design. Wir k├Ânnen nun mit sehr wenig Aufwand daf├╝r sorgen, dass unsere App einen sch├Ânen Rahmen erh├Ąlt und ├╝berall die gleiche Schriftart verwendet wird. Dazu erg├Ąnzen wir in unserer Such-Komponente folgende zwei Imports:

<import rel="import" href="../../bower_components/paper-material/paper-material.html" />
<import rel="import" href="../../bower_components/paper-styles/typography.html" />

Nun umschliessen wir den kompletten Inhalt des Templates mit der soeben importierten paper-material Komponente:

<template>
  <paper-material>
    ...
  </paper-material>
</template>

Jetzt noch schnell etwas eigenen Style hinzugef├╝gt und unsere Buchsuche sieht schon viel gef├Ąlliger aus. Eigene Styles m├╝ssen Bestandteil des Templates sein, d.h. innerhalb des Templates definiert werden:

<template>
  <style>
    * {
      @apply(--paper-font-common-base);
    }
    paper-material {
      padding: 1em;
    }
  </style>
  <paper-material>
    ...
  </paper-material>
</template>

Wir ├╝bernehmen f├╝r alle HTML Elemente die von Polymer f├╝r uns vordefinierte Schrift und setzen f├╝r die paper-material Komponente einen Abstand zum enthaltenen Inhalt. Nun verwendet unsere App ├╝berall die gleiche Schriftart und hat einen sch├Ânen Rahmen.

Responsive Design

Bisher zeigen wir das Suchergebnis untereinander an. Es funktioniert, ist jedoch nicht wirklich responsiv, da der zur Verf├╝gung stehende Platz nicht wirklich genutzt wird. Daher werden wir nun die Komponente f├╝r die Detailansicht erweitern. Dazu importieren wir die Komponente paper-card:

<link rel="import" href="../../bower_components/paper-card/paper-card.html" />

Und ersetzen im Template die Ausgabe des Titels als Absatz durch die paper-card, wobei wir gleich ein paar weitere Angaben ausgeben:

<template>
  <paper-card heading="{{bookdata.volumeInfo.title}}" image="{{bookdata.volumeInfo.imageLinks.thumbnail}}">
    <div id="subtitle">{{bookdata.volumeInfo.subtitle}}</div>
    <div id="details">{{bookdata.volumeInfo.pageCount}} Pages ({{bookdata.volumeInfo.publishedDate}})</div>
  </paper-card>
</template>

Bei der paper-card definieren wir zwei Attribute, eines zur Ausgabe des Buchtitels und eines zur Anzeige des Buchcovers. Innerhalb der paper-card geben wir in einzelnen div-Elementen neu auch den Sub-Titel, die Seitenzahl und das Erscheinungsdatum aus.

Wenn wir das nun im Browser betrachten, sehen wir die entsprechenden Angaben und auch das Buchcover wird angezeigt. Leider alles andere als sch├Ân. Daher f├╝gen wir am Anfang des Templates noch folgendes Stylesheet hinzu:

<style>
  paper-card {
    margin: 1em;
    padding: 0.5em;
    width: 20em;
  }
  #subtitle {
    font-size: 1.2em;
    font-weight: bold;
  }
  #details {
    font-style: italic;
  }
</style>

Wir definieren damit f├╝r die paper-card einige Abst├Ąnde und beschr├Ąnken deren Breite. Auch der Sub-Titel und die Anzeige von Seitenzahl und Erscheinungsdatum sind nun schon etwas gef├Ąlliger. Doch wir haben noch etwas erreicht: Durch die Beschr├Ąnkung der Breite der paper-card werden diese nun nebeneinander angezeigt, je nach zur Verf├╝gung stehendem Platz. Unsere kleine Applikation reagiert jetzt bereits responsiv.

Fremdkomponenten stylen

Der Buchtitel wird von der paper-card ├╝ber dem Buchcover angezeigt. Das w├Ąre nicht weiter schlimm, wenn der Titel jetzt nicht so schlecht zu lesen w├Ąre! Je nach Buchcover ist der Titel gar nicht zu entziffern. Das m├╝ssen wir ├Ąndern. Doch wie?

Jede Komponente hat ihr eigenes kleines DOM, Shadow DOM genannt. Wir k├Ânnen HTML, CSS und JavaScript schreiben, ohne Angst haben zu m├╝ssen, dass dies unerw├╝nschte Nebeneffekte auf andere Komponenten hat. Allerdings haben wir nun ein Problem: Wir k├Ânnen in unserer Komponente so viel CSS definieren, wie wir m├Âchten, die paper-card sieht es schlicht nicht, da sie ihr eigenes DOM hat!

CSS unterst├╝tzt Variablen und so genannte Mixins. Wenn der Autor einer Komponente vorgesehen hat, dass seine Komponente von externen Styles ver├Ąndert werden darf, so stellt er daf├╝r entsprechende Variablen bereit. Welche das sind und was man damit jeweils stylen kann, muss der Autor der Komponente dokumentieren. Google hat das gl├╝cklicherweise f├╝r alle Komponenten des Polymer-Frameworks getan, auch f├╝r die paper-card. Gem├Ąss Dokumentation m├╝ssen wir zum Stylen des Textes ├╝ber dem Bild die Variable --paper-card-header-image-text setzen. Diese Variable ist ein Mixin, d.h. sie enth├Ąlt nicht nur einen Wert, sondern eine komplette CSS-Definition (Name-Wert-Paare). Erg├Ąnzen wir nun das CSS f├╝r die paper-card Komponente wie folgt:

paper-card {
  margin: 1em;
  padding: 0.5em;
  width: 20em;
  --paper-card-header-image-text: {
    color: white;
    font-weight: bold;
    text-shadow:  1px  1px 1px black,
                  1px -1px 1px black,
                 -1px  1px 1px black,
                 -1px -1px 1px black;
  }
}

Wir setzen damit die Schriftfarbe auf weiss, machen den Text fett und f├╝gen noch einen Schatten hinzu, so dass die Schrift schwarz umrandet wird. So ist sie nun auch ├╝ber dem Buchcover sehr gut zu lesen ÔÇö und wir haben ├╝ber ein CSS Mixin in das Styling einer anderen Komponente eingegriffen.

Fazit

F├╝r unsere erste Applikation auf Basis von Web Components und Polymer haben wir einiges geleistet. Wir mussten zwei eigene Komponenten entwickeln und wir haben auf Fremdkomponenten zur├╝ckgegriffen. Mittels eines Polyfills haben wir daf├╝r gesorgt, dass alle aktuellen Browser mit unserer App funktionieren, auch wenn sie noch keine vollst├Ąndige Web Components Unterst├╝tzung implementiert haben.

Wir haben mehrere Komponenten ├╝ber Databinding interagieren lassen und so auch gelernt, wie Daten von einer Komponente an eine andere weitergegeben werden k├Ânnen. Den AJAX-Request zur Suche nach B├╝chern konnten wir komplett ohne JavaScript realisieren. Schliesslich haben wir noch auf das Styling einer Komponente Einfluss genommen und es unseren W├╝nschen angepasst.

Mittels Web Components und Polymer haben wir wiederverwendbare Komponenten entwickelt, die in sich gekapselt sind und die sich kombinieren und erweitern lassen. Dabei haben wir immer ÔÇťin KomponentenÔÇŁ gedacht und auf effiziente weise ├╝bersichtlichen, leicht verst├Ąndlichen Quelltext geschrieben.

Web Components ÔÇö die neue, standardisierte Art, Anwendungen f├╝r das Web zu entwickeln!

Abbildung 5: Unsere fertige Anwendung

Quelltext

Der Quelltext der Beispielanwendung dieses Tutorials steht auf GitHub unter der AGPL zur Verf├╝gung: McPringle/bookworm

Print

Dieses Tutorial wurde auch in gedruckter Form ver├Âffentlicht:

  • JavaPRO 01/2017
  • Java aktuell 04/2017

#html #javascript #webcomponents #polymer #tutorial #javaaktuell #javapro

Enter your email to subscribe to updates.