JavaScript im Theme

Hallo,

ich benötige eigene JavaScript-Funktionen im Theme und bin entsprechend dieser Anleitung vorgegangen:

In der src/Resources/app/storefront/src/main.js habe ich folgendes testweise implementiert:

function showAlert(){
   alert("Das ist ein Test");
}

showAlert();

Nach einem sh ./bin/build-storefront.sh auf der Konsole wird das PopUp im Shop korrekt angezeigt. Wenn ich die Funktion showAlert() aber in einem Twig-Template aufrufe, beispielsweise mit onclick="showAlert();", dann bekomme ich auf der Konsole die Fehlermeldung „Uncaught ReferenceError: showAlert is not defined at HTMLImageElement.onclick“.

Warum komme ich im Twig-Template nicht an die Funktionen heran?

Viele Grüße

… ich beschreibe das Problem nochmal genauer, weil mir da bestimmt jemand einen Tipp geben kann:

Ich erstelle mittels bin/console theme:create ein neues Theme. In der Datei theme.json entsteht dabei auch der Eintrag

"script": [
    "@Storefront",
    "app/storefront/dist/storefront/js/my-theme.js"
  ],

Neuerdings übrigens mit einer falschen Pfadangabe, was dazu führt, dass das frisch erstellte „Standard-Theme“ keinem Verkaufskanal zugeordnet werden kann. Nach einer Korrektur klappt es dann aber.

Danach läuft es eigentlich so, wie unter Add SCSS Styling and JavaScript to a Theme | Shopware Documentation beschrieben:

Wenn man in der Datei /MyTheme/src/Resources/app/storefront/src/js/main.js den JavaScript Code einträgt, speichert und danach auf der Konsole bin/build-storefront.sh ausführt, wird der JS-Code minimiert und unter /MyTheme/src/resources/app/storefront/dist/storefront/js/my-theme.js abgelegt.

Im Beispiel wird der Befehl console.log('SwagBasicExampleTheme JS loaded‘); eingetragen. Dieser Befehl landet auch korrekt in der minimierten Form in /MyTheme/src/resources/app/storefront/dist/storefront/js/my-theme.js Wenn das neue Theme zugewiesen ist und die Storefront aufgerufen wird, sehe ich in der Browser-Konsole auch die Log-Ausgabe. Bis dahin klappt also eigentlich alles, wie beschrieben.

Wenn ich jetzt aber JS-Funktionen erstelle, beispielsweise function showAlert(){alert("test");} die ich später im Twig-Template aufrufen möchte, gibt es die Probleme. Beim späteren Aufruf im Template, über onClick="showAlert();" kommt die Fehlermeldung "Uncaught ReferenceError: showAlert is not defined at HTMLImageElement.onclick“.
Der minimierte JS-Code der Funktion ist auch nicht in /MyTheme/src/resources/app/storefront/dist/storefront/js/my-theme.js enthalten.

Wenn ich nun statt console.log('SwagBasicExampleTheme JS loaded‘); mal die Funktion aufrufe, also showAlert(); dann wird die Funktion bei jeder Seite in der Storefront ausgeführt. Der Aufruf im Template über onClick='…' scheitert aber weiterhin.
In der Datei /MyTheme/src/resources/app/storefront/dist/storefront/js/my-theme.js ist jetzt der folgende Code zu finden: (self.webpackChunk=self.webpackChunk||[]).push([["my-theme"],{5350:()=>{alert("Das ist ein Test")}},e=>{var s;s=5350,e(e.s=s)}]);

Im Endeffekt sieht es so aus, als wenn in /MyTheme/src/resources/app/storefront/dist/storefront/js/my-theme.js immer nur der JS-Code steht, der direkt aufgerufen wird. Der Code von Funktionen fehlt dort.

Wenn ich jetzt den Code der Funktion nachträglich in /MyTheme/src/resources/app/storefront/dist/storefront/js/my-theme.js eintrage, klappt es wieder. Aber dass kann es ja nicht sein. Ich würde also sagen, der grundsätzlich beschriebene Ablauf funktioniert, aber es wird eben nicht der komplette JS-Code minimiert und übertragen.

Wie bekomme ich es hin, das auch der JS-Code meiner Funktionen berücksichtigt wird?

Viele Grüße

Hast du mal versucht, ein Event draufzulegen? In der main.js

const button = document.getElementById('say-hello');

button.addEventListener('click', () => {
    alert('hallo')
})

und dann im Twig
<button id="say-hello">Hello</button>

Empfehlen würde ich aber, das Plugin-System von Shopware zu verwenden.

Hallo @olli.k

danke für Deine Hinweise. In das Thema „Storefront JavaScript plugins with vanilla JavaScript ES6 classes“ muss ich mich dann wohl erstmal mehr einarbeiten. Offenbar kann man, ohne solch ein Plugin, nur begrenzt in Shopware 6 mit JS arbeiten.

Ich hatte zwischenzeitlich noch diese beiden kostenlosen Plugins gefunden:

Damit kann ich meine Dinge erstmal recht gut umsetzen, habe aber wieder den Konflikt, sogar gleich zwei, Plugins einzusetzen, die bei einem der nächsten Updates dann eventuell Probleme machen.

Viele Grüße, Frank

Hallo,

… brauche ich ein separates/eigenes Plugin, wenn ich den JS-Code über den Plugin-Ansatz realisieren will, oder kann ich dass auch innerhalb meines Themes erledigen?

Viele Grüße

okay, habe es einfach mal probiert. Es funktioniert auch im Theme :slightly_smiling_face:.

Viele Grüße

Das Theme ist im Grunde auch nur ein Plugin :slight_smile:

Genau. Da ich sowieso ein eigenes Theme habe, um die Templates anzupassen, kann ich das Thema mit JS gleich mit unterbringen. So benötige ich kein zusätzliches Plugin :slightly_smiling_face:.

Ja, bei uns machen wir das ähnlich. Wir entscheiden nach dem Kontext, wenn es direkt für das Theme passend ist, dann immer ins Theme. Wenn es aber den Shop erweitert, dann machen wir eigene Plugins.

… trotzdem habe ich noch einen merkwürdigen Effekt:

// <plugin root>/src/Resources/app/storefront/src/my-theme/my-theme.plugin.js
import Plugin from 'src/plugin-system/plugin.class';

export default class MyTheme extends Plugin {
    static options = {
        /**
         * @type string
         */
        text: 'Seems like there\'s nothing more to see here.',
    };

    init() {
        window.addEventListener('click', this.onClick.bind(this));
    }

    onClick() {
        console.log(this.options.text);
    }
}

Ich habe das mal umgebaut für das Click-Event, da ich ein zusätzliches Element im Listing benötige, was durch Klicken auf ein Symbol in der Produkt-Box ausgelöst werden soll.

Im Listing habe ich mal zu Testzwecken folgendes eingebaut:

{% set examplePluginOptions = {
         text: product.translated.name
} %}

<button data-my-theme data-my-theme-options='{{ examplePluginOptions|json_encode }}'>Klick mich...</button>

Wenn ich jetzt auf den neuen Button klicke, erscheint die Ausgabe in der Konsole. Allerdings für alle Produktboxen, die im Listing vorhanden sind. Ich möchte aber nur die eine, wo ich geklickt habe?

du musst das anders machen

    init() {
        this.el.addEventListener('click', this.onClick.bind(this));
    }

Super! Das funktioniert prima. Genau das ist für mich der Lösungsweg.

Viele Dank!

1 „Gefällt mir“

Das ist doof aus der Doku, denn da wird das scroll event angesprochen, welches für das komplette Fenster gilt window. Du willst aber nur das Element. Dadurch das du von Plugin erbst, hast du mit this.el zugriff auf das Element auf welches du regieren willst

Dieses Thema wurde automatisch 30 Tage nach der letzten Antwort geschlossen. Es sind keine neuen Antworten mehr erlaubt.