Erfassen Sie Ihre Fortschritte
Trailhead-Startseite
Trailhead-Startseite

Verarbeiten von Aktionen mit Controllern

Lernziele

Nachdem Sie diese Lektion abgeschlossen haben, sind Sie in der Lage, die folgenden Aufgaben auszuführen:
  • Erstellen eines clientseitigen Controllers, um Aktionen zu verarbeiten
  • Lesen von Werten aus Attributen von Komponenten
  • Lesen von Werten aus Steuerelementen auf der Benutzeroberfläche in Ihrer Komponente
  • Schreiben von Controllercode in JavaScript zum Ändern der Benutzeroberfläche

Verarbeiten von Aktionen mit Controllern

Bislang haben wir nur mit XML-Markup gearbeitet. Bislang bestand unsere einzige Möglichkeit, die Ausgabe unserer Komponente zu ändern, in der Änderung des Markups. Bislang haben unsere Komponenten nicht auf Benutzereingaben reagiert. Bislang haben wir kein JavaScript geschrieben.

Das alles ändert sich in dieser Einheit.

Lassen Sie uns zum Einstieg eine sehr einfache Komponente ansehen und uns vorstellen, was sie benötigt, um ihr einfaches Verhalten verarbeiten zu können.

Meldung des Tages: Schaltfläche 'You look nice today', Schaltfläche 'Today is going to be a great day'

Dies ist helloMessageInteractive und es ist nur schwer vorstellbar, sich eine einfachere Komponente vorzustellen, die "etwas macht". Es handelt sich um etwas statischen Text, eine (derzeit leere) Meldung und zwei Schaltflächen. Der Code sieht folgendermaßen aus:

<aura:component>
    <aura:attribute name="message" type="String"/>
    <p>Message of the day: {!v.message}</p>
    <div>
        <lightning:button label="You look nice today."
            onclick="{!c.handleClick}"/>
        <lightning:button label="Today is going to be a great day!"
            onclick="{!c.handleClick}"/>
    </div>
</aura:component>

Das sollte Ihnen bekannt vorkommen. Wir haben nichts weiter gemacht, als zwei Komponenten des Typs <lightning:button> zu helloMessage hinzuzufügen. Wenn Sie auf eine Schaltfläche klicken, wird die Meldung des Tages aktualisiert.

Nun, noch nicht ganz. Wenn Sie den Code bereits eingegeben haben und es selbst ausprobiert haben, haben Sie bemerkt, dass Sie eine Fehlermeldung erhalten, sobald Sie auf eine der Schaltfläche klicken.

Ein Problem liegt vor

Wir sind die ersten, die zugeben, dass nicht jede Fehlermeldung, die Ihnen in Lightning Components angezeigt wird, so hilfreich wie vielleicht gewünscht ist. Diese aber schon! Sie besagt, dass es keine Controlleraktion namens "handleClick" gibt. Woher stammt "handleClick"? Vom Ausdruck, den wir dem Attribut onclick für die beiden <lightning:button>-Tags zugewiesen haben:

onclick="{!c.handleClick}"

Angesichts der Tatsache, dass dies eine Schaltfläche ist, können Sie sich bestimmt denken, dass das Attribut onclick dazu dient, der Schaltfläche ein Verhalten zuzuweisen, wenn auf sie geklickt wird. Doch was haben wir zugewiesen? Einen Ausdruck, {!c.handleClick}, was vielleicht ein wenig mysteriös ist.

Aber eigentlich ist es ziemlich einfach. Ebenso wie der Ausdruck v.message von vorhin, ist c.handleClick ein Wertanbieter, d. h. c mit der Eigenschaft handleClick. c ist der Wertanbieter für den clientseitigen Controller der Komponente. handleClick ist eine in diesem Controller definierte Funktion. {!c.handleClick} ist also ein Verweis auf einen Aktionshandler im Controller der Komponente.

c.handleClick: 'c' ist der Wertanbieter für den Controller der Komponente, 'handleClick' eine Eigenschaft, d. h. eine in diesem Controller definierte Funktion.

Was ist überhaupt ein Controller?

Hoppla! Ein Controller ist im Wesentlichen eine Sammlung von Code, die das Verhalten Ihrer Anwendung definiert, wenn "etwas passiert". Unter "etwas" verstehen wir eine Benutzereingabe, einen Timer und andere Ereignisse, Datenaktualisierungen usw. Wenn Sie auf einer der Websites für Entwickler "Model-View-Controller" nachschlagen, erhalten Sie eine Vielzahl von Definitionen. In Lightning Components ist ein Controller eine Ressource in einem Komponentenpaket, die die Aktionshandler für diese Komponente enthält. Aktionshandler sind JavaScript-Funktionen mit einer bestimmten Funktionssignatur.

Über die Grundlagen hinaus

In dieser Lektion wird viel von Controllern die Rede sein und wir wissen, dass die Komponente selbst eine Ansicht ist. Wir haben sogar das Entwurfsmuster "Model-View-Controller" (MVC) bereits erwähnt, das in Webanwendungs-Frameworks so gängig ist. Basiert Lightning Components auf dem MVC-Muster?

Kurz gesagt, nein. Es gibt sicherlich Ähnlichkeiten, doch eher stimmt, dass Lightning Components entweder View-Controller-Controller-Model oder vielleicht View-Controller-Controller-Database entspricht.

Warum kommt "Controller" in diesem Musternamen doppelt vor? Weil Ihre Komponenten bei der Interaktion mit Salesforce zusätzlich zum clientseitigen Controller, mit dem wir in dieser Einheit gearbeitet haben, über einen serverseitigen Controller verfügen. Dieses Zwei-Steuerfeld-Muster ist der Hauptunterschied zwischen Lightning Components und MVC.

Was ist der Unterschied zwischen "Modell" und "Datenbank"? Beim herkömmlichen MVC-Muster ist das Modell eine programmgesteuerte Abstraktion (meist eine Klasse) zwischen dem zugrunde liegenden Datenspeicher (meist eine relationale Datenbank) und der restlichen Anwendung. In Lightning Components gibt es keine Apex-Klasse, die sich direkt zwischen @AuraEnabled-Controllermethoden und DML-Vorgängen befindet. Doch andererseits sind sObjects bereits eine Abstraktion zwischen Ihrem Apex-Code und der zugrunde liegenden Speicherebene. Sie können Berechnungsfelder, Validierungslogik und sogar ein vollständig programmgesteuertes Verhalten in Form von Auslösern hinzufügen. Handelt es sich um eine Datenbank oder ein Modell? Wir sagen "dies", es ist aber völlig okay, wenn Sie "das" sagen.

Verwirrt? Gespannt? Die Einzelheiten zu serverseitigen Controllern werden wir Ihnen in einer späteren Lektion erläutern.

Lassen Sie uns den Controller helloMessageInteractive im Detail betrachten, um die Erläuterung ein wenig zu konkretisieren.

({
    handleClick: function(component, event, helper) {
        let btnClicked = event.getSource();         // the button
        let btnMessage = btnClicked.get("v.label"); // the button's label
        component.set("v.message", btnMessage);     // update our message
    }
})

Controllerressourcen haben ein interessantes Format. Es handelt sich um JavaScript-Objekte, die eine Zuordnung von Name/Wert-Paaren enthalten. Dabei gehört Name zum Aktionshandler und der Wert zu einer Funktionsdefinition.

Aktionshandler

Die Kombination eines Name/Wert-Paars und einer bestimmten Funktionssignatur wird als Aktionshandler bezeichnet. Sie werden feststellen, dass die Begriffe Aktionshandler, Controlleraktion und Controllerfunktion austauschbar verwendet werden, was meist unproblematisch ist. Sie verweisen fast immer auf dasselbe. (Die Ausnahmen lassen wir in diesem Modul einmal außen vor.)

Machen Sie sich nicht zu viele Gedanken wegen des besonderen Formats der Controllerressource. Wenn Sie in der Entwicklerkonsole auf die Schaltfläche CONTROLLER klicken, erhalten Sie eine Controllerressource mit einem bereits hinzugefügten Aktionshandler. Wichtig ist jedoch, dass Sie die Aktionshandler mit Kommas voneinander trennen, da sie andernfalls Syntaxfehler erhalten. Dies ist JavaScript-Standardsyntax, deren Besonderheiten wir im weiteren Verlauf veranschaulichen.

Die tatsächliche handleClick-Funktion besteht nur aus vier Codezeilen, die aber ggf. anfänglich schwer verständlich sind. Allgemein gesehen ist alles einfach: Wenn auf die Schaltfläche geklickt wird, wird der Aktionshandler aufgerufen (1). Im Aktionshandler ruft der Controller die Schaltfläche ab, auf die geklickt wurde, extrahiert daraus den Beschriftungstext und legt das message-Attribut der Komponente auf diesen Text fest (2). Daraufhin wird die Meldung des Tages aktualisiert (3). You look nice today!

Im Aktionshandler ruft der Controller den Text der Schaltfläche ab, auf die geklickt wurde, und legt das 'message'-Attribut der Komponente fest

Einfach, nicht wahr? Nun ja...

Da dies überaus wichtig ist, gehen wir das Ganze Zeile für Zeile durch.

handleClick: function(component, event, helper) {

Auf den Namen des Aktionshandlers folgt eine anonyme Funktionsdeklaration. Der wichtige Aspekt ist hier die Funktionssignatur. Wenngleich technisch nicht erforderlich, sollten Sie stets Ihre Controllerfunktionen so deklarieren, dass diese drei Parameter verwendet werden. Wir werden auf diese im weiteren Verlauf noch eingehen, doch für den Moment stellen diese Parameter Folgendes dar:

  • component: Die Komponente. Sie heißt hier helloMessageInteractive.
  • event: Das Ereignis, das den Aufruf des Aktionshandlers verursacht hat.
  • helper: Die Hilfsfunktion der Komponente, eine weitere JavaScript-Ressource mit wiederverwendbaren Funktionen.
    let btnClicked = event.getSource();         // the button

Wie Sie sich erinnern, ist handleClick mit unserem <lightning:button>-Tag und seinem onclick-Attribut verbunden. Das event (Ereignis) ist das Klicken auf die Schaltfläche. Innerhalb dieses Ereignisses hat diese das Konzept einer Quelle (eines Elements, welches das Ereignis generiert hat), die die Schaltfläche selbst ist. Durch Aufrufen von event.getSource() erhalten wir einen Verweis auf die bestimmte Schaltfläche <lightning:button>, auf die geklickt wurde.

    let btnMessage = btnClicked.get("v.label"); // the button's label

Was tun wir nun, da wir über einen Verweis auf die Schaltfläche verfügen? Wir gucken in sie hinein und rufen ihre Beschriftung ab, die für <lightning:button> im Markup der Komponente festgelegt wird. Beispiel: <lightning:button label="You look nice today." ... >.

Lassen Sie uns das ein wenig näher untersuchen. Wir haben die Definition von <lightning:button> nicht unmittelbar vor uns, aber label ist lediglich ein weiteres Attribut, vergleichbar mit dem message-Attribut, das wir helloMessageInteractive hinzugefügt haben. Sie können get() für jede Komponente aufrufen und den Namen des Attributs angeben, das Sie abrufen möchten, und zwar im Format v.attributeName. Das Ergebnis ist der Attributwert.

Beachten Sie, dass v wie im Markup der Komponente die Ansicht, also die Komponente selbst darstellt. Doch in diesem Fall handelt es sich um die untergeordnete Komponente <lightning:button> und nicht um helloMessageInteractive! Stellen Sie sich das folgendermaßen vor. btnClicked.get("v.label") tippt der Komponente btnClicked auf die Schulter und sagt "Hallo, gib mir bitte 'v.label'". Die Komponente denkt "v, das bin ich", guckt in sich hinein und gibt den Wert ihres Beschriftungsattributs zurück.

Nachdem wir eine Textzeichenfolge aus der Schaltfläche abgerufen haben, bleibt nur noch ein Schritt, nämlich das Ändern des message-Attributs in den neuen Meldungstext. So wie mit get() ein Wert aus einer Komponente gelesen wird, dient set() zum Schreiben eines Werts.

    component.set("v.message", btnMessage);     // update our message

Lassen Sie uns jedoch einen wichtigen Unterschied anmerken. Wir haben get() für btnClicked aufgerufen, die <lightning:button>, die sich in helloMessageInteractive befindet. set() rufen wir für component auf, d. h. für die Komponente helloMessageInteractive selbst. Dieses Muster wiederholen Sie bei praktisch jeder Komponente, die Sie erstellen: Abrufen von Werten aus untergeordneten Komponenten, Anwenden einer Verarbeitung und Festlegen von Werten in der Komponente selbst.

Das View-Controller-Programmierungsmodell von Aura-Komponenten

Was sagt das Bauchgefühl? Alles klar? Sicher? Wenn Sie sagen, Ich denke schon, vergewissern Sie sich, dass Sie die Komponente helloMessageInteractive mithilfe des vorstehenden Codes erstellt haben. Es ist bloß eine Komponente und das Kopieren und Einfügen des Codes dauert zwei Minuten. Doch die Fähigkeit, damit zu spielen, ist wesentlich für das Verstehen von Verarbeitungsaktionen.

Was Sie gerade hier gemacht haben, scheint sehr einfach, da es nicht sehr viele Codezeilen sind. Doch diese Codezeilen veranschaulichen einige der grundlegenden Konzepte der Entwicklung von Anwendungen mit Aura-Komponenten.

Sie können sich das Verknüpfen von Komponenten mit Aktionshandlern als eine Art "Verschaltung" vorstellen. Stellen Sie sich helloMessageInteractive als einfachen elektrischen Schaltkreis vor. Zum einen sind da Schalter, zum anderen Glühlampen. (Das Lightning Components-Framework liefert den Strom.) Für sich genommen macht ein Schalter vielleicht ein nettes Klickgeräusch, doch ohne Verschaltung ist er nicht besonders praktisch. Sie können die schickste Edison-Glühlampe haben, doch solange sie nicht verschaltet ist, leuchtet nichts.

Das gilt so auch für Aura-Komponenten. Zuvor haben wir einmal gesagt, dass die verschiedenen Ressourcen in einem Komponentenpaket automatisch miteinander verknüpft sind. Und das stimmt, denn die Verknüpfung wird durch die Wertanbieter v und c ermöglicht. Sie werden automatisch erstellt und in Ihren Komponenten verfügbar gemacht, sodass Ihr Controller auf die Komponente verweisen kann und umgekehrt. Doch diese automatische Verknüpfung erfolgt nur auf einer hohen Ebene, und zwar in helloMessageInteractive zwischen der CMP-Ressource der Komponente und der JS-Ressource des Steuerfelds. Dies ist der grüne Pfeil in der folgenden Abbildung.

'helloMessageInteractive' und sein Steuerfeld sind automatisch miteinander verknüpft

Die Verknüpfung zum Verbinden einer bestimmten <lightning:button>-Komponente mit einem bestimmten Aktionshandler, d. h. das Verknüpfen von Dingen, die Ereignisse generieren (z. B. Schaltflächen), mit Dingen, die Ereignisse verarbeiten (z. B. eine bestimmte Controllerfunktion), müssen Sie selbst vornehmen. Und nichts anderes haben Sie gerade bereits getan! Dies sind die roten Pfeile, die zum Vervollständigen eines funktionierenden Schaltkreises benötigt werden.

Durch das Hinzufügen von {!c.handleClick} zum onclick-Attribut einer <lightning:button>-Komponente (1) erfolgt eine Verknüpfung mit dem spezifischen Aktionshandler. Durch Aufrufen von component.set("v.message", newMessage) (2) wird das Ergebnis des Aktionshandlers mit dem message-Attribut der Komponente verknüpft. Dieser ist wiederum mit einem {!v.message}-Ausdruck verknüpft.

Sie können sich weiter das onclick-Ereignis als ein Elektron vorstellen, das durch den von Ihnen erstellten Schaltkreis fließt. Wenn Sie keinen vollständigen Schaltkreis erstellt haben, verpufft das Ereignis ergebnislos. Wenn Sie beginnen, Ihre eigenen Komponenten zu schreiben, behalten Sie dies im Hinterkopf. Haben Sie einen vollständigen Schaltkreis? Sind Sie sicher? Im Zweifelsfall ist es mitunter hilfreich, alles auf einem Whiteboard oder auf Papier zu skizzieren und alle Verbindungen zu überprüfen.

Sie verbinden Komponenten, Ereignisse und Handler auf niedrigen und hohen Ebenen, sodass Sie sich oft wie ein Elektriker fühlen. (Oder angesichts des Namens des Frameworks wie Benjamin Franklin.) Die Verknüpfung von Dingen miteinander ist für das Programmiermodell von Aura-Komponenten von grundlegender Bedeutung.

Und genau das wollen wir nun vertiefen. Schließlich macht Übung den Meister.

Verketten und Neuverknüpfen von Funktionen und einfaches Debuggen

Unsere erste Version von handleClick bestand aus drei Codezeilen, da wir jeden Schritt im Muster "Abrufen-Verarbeiten-Festlegen" (get-process-set) in getrennte Zeilen aufgeteilt haben. Sie können mit einer Funktionsverkettung arbeiten, um eine Verringerung auf weniger Zeilen zu erreichen. Da Sie dies wahrscheinlich schon in anderem Lightning Components-Code gesehen haben, lassen Sie es uns einmal ausprobieren. Fügen Sie den folgenden Code Ihrem helloMessageInteractive-Controller hinter handleClick zu.

    handleClick2: function(component, event, helper) {
        let newMessage = event.getSource().get("v.label");
        component.set("v.message", newMessage);
    },
    handleClick3: function(component, event, helper) {
        component.set("v.message", event.getSource().get("v.label"));
    }

Ohh! Ist ein Syntaxfehler aufgetreten, als Sie versucht haben zu speichern? Erinnern Sie sich noch, dass wir erwähnt hatten, dass Sie Kommas zwischen Ihre Aktionshandler setzen müssen? Das ist das Problem hier. Setzen Sie hinter der schließenden geschweiften Klammer ("}") von handleClick ein Komma (siehe das Ende von handleClick2 im vorherigen Codeausschnitt).

Diese Aktionshandler machen genau dasselbe wie handleClick, jedoch in weniger Codezeilen. Hierzu überspringen sie Zwischenvariablen (häufig durch direktes "Verketten" mit dem nächsten Funktionsaufruf), indem der jeweilige Aufruf am Ende des vorhergehenden durch einen Punkt getrennt hinzugefügt wird. (Dieses Konzept wird am deutlichsten, wenn Sie sich die Unterschiede zwischen handleClick und handleClick2 ansehen.)

Welchen Stil Sie bevorzugen, ist eine Frage des persönlichen Geschmacks und ggf. des Programmierstils Ihrer Organisation. Ihr bescheidener Autor bevorzugt handleClick2 und das Trennen von get und set, ohne sich mit einer Variablen für die Schaltfläche zu beschäftigen, die wir nur für deren Beschriftungstext benötigen.

Sie können freilich erst bestätigen, dass die neuen Aktionshandler funktionieren, nachdem Sie eine <lightning:button>-Komponente für die Verwendung von einem davon eingerichtet haben, indem Sie das onclick-Attribut {!c.handleClick2} oder {!c.handleClick3} festlegen. Stellen Sie sich dies als Trennen der Drähte von einer Glühlampe und Verbinden dieser Drähte mit einer anderen Glühlampe vor. So einfach ist das!

An dieser Stelle laden Sie die Anwendung neu, klicken auf eine der neu verknüpften Schaltflächen, und nun ja, sie ist immer noch dieselbe, oder nicht? Wie können wir überhaupt bestimmen, welcher Aktionshandler aufgerufen wird?

Manchmal ist einfach am besten. Lassen Sie uns einer der Aktionshandlerfunktionen eine Protokollierung hinzufügen:

    handleClick2: function(component, event, helper) {
        let newMessage = event.getSource().get("v.label");
        console.log("handleClick2: Message: " + newMessage);
        component.set("v.message", newMessage);
    },

Wenn Sie nun eine <lightning:button>-Komponente mit handleClick2 verknüpfen, wird in der JavaScript-Konsole in Ihrem Browser eine Protokollmeldung angezeigt, wenn Sie darauf klicken.

Ja, es gibt ausgeklügeltere Debug-Tools, doch die Ausgabe von Meldungen in der Konsole ist eine althergebrachte Debug-Methode. Wenn Sie ein beliebiges Objekt ausgeben möchten, umschließen Sie es mit JSON.stringify(IhrObjekt , um noch nützlichere Details zu erfahren. Wenn Sie einen Schnelleinblick wünschen, ist console.log() besonders gut geeignet.

Wir behandeln diese anspruchsvolleren Debug-Tools und -Methoden nicht weiter. Unter "Ressourcen" finden Sie Links zu sehr nützlichen Tools und Anweisungen.

OK, helloMessageInteractive war schön einfach und hatte eine hartcodierte (und gnadenlos positive) Attitüde. In der nächsten Einheit arbeiten wir mit einem komplexeren Beispiel und erfahren, wie echte Benutzereingaben erfasst werden. Und da Menschen in der realen Welt nicht immer so positiv sind, erfahren Sie auch, wie wir ihre Eingaben überprüfen.