Webkomponenten Teil 2: Erstellen einer Magnolia-Webkomponente
In meinem letzten Blog-Beitrag "Web Components Part 1: Exploring Reusable Web Components" habe ich Web Components als eine Möglichkeit zur Bewältigung der Herausforderungen neuer Front-End-Frameworks und -Technologien, die ständig auftauchen, untersucht. Indem sie es Entwicklern ermöglichen, wiederverwendbare Elemente zu erstellen, machen Web Components das Leben für uns viel einfacher.
In diesem Beitrag zeige ich Ihnen, wie Sie eine Webkomponente mit dem Namen "hierarchical-browser" erstellen können, um eine hierarchische Datenstruktur mit JavaScript und verschiedenen Magnolia-Funktionen zu navigieren, darunter unser Low-Code-Entwicklungsansatz, Inhaltstypen und unsere Delivery-API. Der Quellcode ist auf GitHub verfügbar.
Magnolia-Einrichtung
Mit YAML habe ich eine Magnolia Content App mit Magnolia Light Development, unserem Low-Code Entwicklungsansatz, erstellt. Wenn Sie mit Light Development noch nicht vertraut sind, können Sie sich unser Hello Magnolia-Tutorial ansehen.
Der Quellcode auf GitHub enthält bereits ein ganzes Magnolia-Light-Modul namens "cars", einschließlich der Content-App "cars-app", des Content-Typs "cars", der Seitenvorlage und der Webkomponente.
cars ├── apps │ └── cars-app.yaml <-- Inhalt app ├── contentTypes │ └── cars.yaml <-- Inhaltstyp ├── restEndpoints │ └── delivery │ └── cars.yaml <-- Auslieferungsendpunkt ├── templates │ └── pages │ ├── main.ftl <-- Seite mit Webkomponente │ └── main.yaml <-- Seitendefinition └── webresources └── hierarchical-browser.js <-- Webkomponente
Sobald Sie den Code in Ihre Magnolia-Instanz geklont haben, öffnen Sie die Anwendung und geben Sie einige erste Daten ein:
Um Frontends die Abfrage dieser Daten über die API zu ermöglichen, habe ich eine Endpunktdefinition in cars/restEndpoints/delivery/cars.yaml hinzugefügt. Der cars-Endpunkt macht Inhalte aus dem cars-Arbeitsbereich verfügbar, in dem Magnolia alle cars-Inhalte hierarchisch speichert.
Damit die Benutzer diese Inhalte sehen können, müssen wir den anonymen Zugriff auf den Arbeitsbereich der Autos zulassen, da wir keinen Authentifizierungsmechanismus für diesen REST-Client verwenden.
Öffnen Sie die App "Sicherheit", gehen Sie auf die Registerkarte "Rollen" und bearbeiten Sie die Rolle "Anonym". Dann die Registerkarte "Zugriffskontrolllisten" und fügen Sie Lese-/Schreibzugriff für den Arbeitsbereich "Cars" hinzu.
Sie können die Antwort der Delivery API mit überprüfen:
curl -v "http://localhost:8080/magnoliaAuthor/.rest/delivery/cars" curl -v "http://localhost:8080/magnoliaAuthor/.rest/delivery/cars/Mercedes"
Wir haben jetzt:
Inhalt im Arbeitsbereich des Autos
Ein öffentlicher Endpunkt zum Abrufen von Daten
Anonymer Zugriff auf die Inhalte im Arbeitsbereich des Autos
Um die Seite mit der Webkomponente in Magnolia zu sehen, öffnen Sie die Pages-App und fügen Sie eine neue Seite mit der Vorlage <Hauptseite> hinzu.
Wenn Sie die Seite öffnen, sollten Sie dies sehen:
Sie können auf eine gelbe Zeile klicken, um einen Ordner zu öffnen und den darin enthaltenen hierarchischen Inhalt zu sehen.
Werfen wir nun einen Blick auf den Code.
JavaScript REST-Client
Die Funktionen am Anfang von hierarchical-browser.js verarbeiten die HTTP-REST-Aufrufe zum Abrufen der Daten vom Endpunkt:
const getClient = (baseUrl, endpointName) => { return { baseUrl: baseUrl, endpointName: endpointName, getItems: function getItems(path) { return clientFunctions.makeCall(this.baseUrl + '/.rest/delivery/' + endpointName + path + '@nodes').then(function (data) { return JSON.parse(data); }).then((json) => { return json.map(jsonToItem); }); } }; }; const jsonToItem = (data) => { var map = new Map(Object.entries(data)).set('isFolder', data['@nodeType'] === 'mgnl:folder'); map['delete']('@nodes'); map['delete']('@nodeType'); return map; }; const makeCall = (url) => { return new Promise((resolve, reject) => { var request = new XMLHttpRequest(); request.open('GET', url); request.onload = () => { if (request.status === 200) { resolve(request.response); } else { reject(Error('Fehler beim Aufruf von ' + url + '; Fehlercode:' + request.statusText)); } }; request.onerror = () => { reject(Error('Es gab einen Netzwerkfehler beim Aufruf von ' + url)); }; request.send(); }); }; const clientFunctions = { makeCall: makeCall, getClient: getClient };
<getClient> ruft einen Client auf, der den Server anruft. Dann verarbeitet die asynchrone Funktion <getItems> die resultierende Karte, um Elemente aus einem bestimmten Pfad zu erhalten. Die JSON-Antwort wird dann in eine Liste von Maps umgewandelt.
Im nachfolgenden JavaScript-Code wird der Client im Konstruktor initialisiert, und <getItems> wird von <loadItems> jedes Mal aufgerufen, wenn ein Benutzer die Elemente in einem bestimmten Pfad sehen möchte.
Hierarchische Browser-Webkomponente
Werfen wir einen Blick auf die Verwendung der Komponente in templates/pages/main.ftl:
<hierarchical-browser baseUrl="${ctx.contextPath}" endpoint="cars" columns="name,model,power"></hierarchical-browser>
Die <baseUrl> ist die anfängliche URL, die der REST-Client für seine Aufrufe verwendet. In unserem Beispiel lautet die <baseUrl> http://localhost:8080/magnoliaAuthor.
Der Parameter <Endpunkt >ist der Name des Endpunkts, wie er im Ordner restEndpoints/delivery angegeben ist.
Der Parameter <columns> ist eine durch Kommata getrennte Liste, die die abzurufenden Inhaltstypfelder angibt. Sie können alle Felder angeben, die in contentTypes/cars.yaml definiert sind.
Die Webkomponente selbst ist nur eine Tabelle, in der die ausgewählten Spalten angezeigt werden. Anklickbare Elemente, d. h. Ordner, sind gelb. Die Tabelle ist einfach zu bedienen: Sie können durch die Baumstruktur navigieren, indem Sie auf einen Ordner klicken. Wenn Sie sich in einem Unterordner befinden, können Sie auf den übergeordneten Ordner klicken.
Verwaltung des Zustands der Komponente
Webkomponenten haben die Möglichkeit, Änderungen von Attributen mit Hilfe der Funktion <attributeChangedCallback> zu beobachten. Wenn sich eines der beobachteten Attribute ändert, löst die Komponente eine Aktion aus.
Unsere Webkomponente achtet auf Änderungen in der Eigenschaft <state> und ruft die Funktion <render> auf, wenn sich diese Eigenschaft ändert:
get state() { return this.getAttribute('state'); } set state(value) { this.setAttribute('state', value); } static get observedAttributes() { return ['state']; } attributeChangedCallback(name, oldValue, newValue) { this.render(); }
Wir brauchen die Funktion <connectedCallback> nicht zu überschreiben. Der Konstruktor legt den Anfangszustand der Komponente fest, und der Zustand entwickelt sich mit den REST-Aufrufen, die durch die Interaktion des Benutzers ausgelöst werden. Jedes Mal, wenn der Benutzer auf einen Ordner klickt, macht die Webkomponente einen neuen Aufruf, um den Inhalt vom Server zu holen, und wir fügen ein Ereignis mit !#<addFolderClickEvent>#! hinzu. Der Zustand ist <loading> während wir Daten vom Server holen, <ready> sobald die Daten angekommen sind, oder <error>.
Schablonieren
Die Erstellung des HTML-Codes der Webkomponente war die zeitaufwändigste Aufgabe. Aufgrund des Templating-Systems von Web Component musste ich zu viel Präsentationscode hinzufügen, was nicht dazu beitrug, Logik und Präsentation zu trennen.
Wie ich bereits in einem früheren Beitrag erwähnt habe, sind HTML-Vorlagen gut für statische Inhalte, aber nicht ideal für das Hinzufügen dynamischer Inhalte, da sie nicht vielseitig genug sind.
Ich empfehle Ihnen dringend, ein Webkomponenten-Framework oder zumindest eine hybride Template-Lösung zu verwenden. Verwenden Sie zum Beispiel HTML-Vorlagen für statische Inhalte und eine Vorlagenbibliothek wie Mustache oder Handlebars für dynamische Inhalte.
Übung zur Webkomponente
Nachdem Sie nun einen Blick auf meinen Code geworfen und die Webkomponente in Aktion gesehen haben, möchten Sie vielleicht selbst etwas programmieren. In diesem Fall möchte ich Ihnen eine Übung anbieten, um Ihr Wissen über Webkomponenten und Magnolia zu erweitern.
Wenn Sie das Lichtmodul implementiert und Autos in der Content-App hinzugefügt haben, erinnern Sie sich vielleicht daran, dass Sie in den Autoeigenschaften ein optionales Bild aus dem Magnolia DAM hinzufügen konnten.
Das Bild wird in der Konfigurationsdatei des Inhaltstyps, cars.yaml, definiert:
model: properties: - name: image type: asset
Das Bild ist jedoch noch nicht Teil der Webkomponente. Dies ist also Ihre Aufgabe: Ändern Sie den Code so, dass das Bild angezeigt wird, wenn ein Benutzer auf eine Autozeile klickt, d. h. auf einen Inhalt, der nicht in einem Ordner enthalten ist.
Fühlen Sie sich frei, das GitHub-Repository zu forken und Pull Requests mit dieser Übung, anderen Übungen, Korrekturen oder Verbesserungen zu senden. Ich werde sie sehr gerne einbinden.
Investitionen in die Zukunft der Webentwicklung
Der Web Components Standard bietet wiederverwendbare Komponenten für die Webentwicklung. Die Erstellung von Webkomponenten ist eine Investition in die Zukunft, da Komponenten überall, mit jedem JavaScript-Framework und in jeder HTML-Umgebung verwendet werden können.
Der Anwendungsfall Autos ist ein gutes und einfaches Beispiel, um zu lernen, wie man eine Webkomponente erstellt. Es zeigt auch die Probleme mit HTML-Vorlagen. Ich habe zwar nicht alle Details erklärt, aber die Grundlagen, damit Sie verstehen, was die Webkomponente tut. Wenn Sie tiefer einsteigen wollen, sollten Sie sich den Code für die Logik zur Verwaltung des übergeordneten Ordners, den HTTP-Client-Code und die Dom-Manipulation ansehen.
Wenn Sie sich für fortgeschrittenere Funktionen von Web Components interessieren, wie z.B. Web Components Kommunikation, Testen oder Schatten-CSS, empfehle ich Ihnen meinen vorherigen Blogbeitrag "Web Components Part 1: Exploring Reusable Web Components" und dessen Quellcode auf GitHub.
Ich hoffe, es hat Ihnen Spaß gemacht, diese Webkomponente zu erstellen und mit Magnolia zu arbeiten!