Verwendung von Knockout JS in Magento 2


12

Mein Problem:

Ich versuche, eine kleine Knockout JS-App in Magento 2 zu schreiben. Ich habe Probleme, die App so zu initialisieren, dass bei Verwendung ko.applyBindings(AppViewModel, document.getElementById("koTest"));der von Magento verwendete Knockout unterbrochen wird und der folgende Fehler ausgelöst wird:

Uncaught Error: You cannot apply bindings multiple times to the same element.

Ich vermute, es liegt an:

Ich vermute , das liegt daran , dass Magento 2 bereits verwendet ko.applyBindings()innerhalb app/code/Magento/Ui/view/base/web/js/lib/knockout/bootstrap.js. Und da dies keinen Knoten angibt, kann ich ihn nicht mehr verwenden ko.applyBindings.

Wenn ich ko.applyBindings(AppViewModel, document.getElementById("koTest"))meinen Code nicht verwende, wird meine App nicht initialisiert.

Das lässt mich denken, dass ich irgendwie die ko.applyBindings()in knockout / bootstrap.js verwenden muss, aber ich habe keine Ahnung wie, kann jemand helfen? Ich habe wenig Erfahrung mit Knockout.

Mein Code

<script type="text/javascript">
    require([
        'ko'
    ], function(ko) {
        // This is a simple *viewmodel* - JavaScript that defines the data and behavior of your UI
        function AppViewModel() {

            this.firstName = ko.observable("Bert");
            this.lastName = ko.observable("Bertington");
            this.fullName = ko.computed(function() {
                return this.firstName() + " " + this.lastName();
            }, this);

            this.capitalizeLastName = function() {
                var currentVal = this.lastName();
                this.lastName(currentVal.toUpperCase());
            };
        }

        ko.applyBindings(AppViewModel, document.getElementById("koTest"));
    });
</script>

<!-- This is a *view* - HTML markup that defines the appearance of your UI -->

<div id="koTest">
    <p>First name: <strong data-bind="text: firstName"></strong></p>
    <p>Last name: <strong data-bind="text: lastName"></strong></p>
    <p>Full name: <strong data-bind="text: fullName"></strong></p>

    <p>First name: <input data-bind="value: firstName" /></p>
    <p>Last name: <input data-bind="value: lastName" /></p>
    <p>Full name: <input data-bind="value: fullName" /></p>

    <button data-bind="click: capitalizeLastName">Capitalise</button>
</div>

Antworten:


23

Einfache Methode, bei der Sie KEINE HTML-Vorlagen verwenden müssen

Dank Vinai Kopp habe ich endlich eine Antwort darauf erhalten. Es ist viel einfacher als meine vorherige hackige Problemumgehung (ich habe Knoten gesäubert). Sie müssen lediglich 'ko'eine Abhängigkeit definieren und Ihren Code in eine Rückgabefunktion einfügen.

Im Folgenden finden Sie ein einfaches Beispiel, in dem über JSON übergebener Text gerendert wird.

app/code/VENODR/MODULE/view/frontend/templates/knockout-example.phtml

Hier teilen wir Magento den Umfang unserer Komponenten mit (dies muss mit data-bind: "scope: 'example-scope'"zusätzlichen Daten übereinstimmen und diese übergeben. Dies kann die Basis-URL sein, eine einfache Nachricht, so ziemlich alles, was Sie wollen. Ich habe als Beispiel eine Zeichenfolge (PHP-Echo) übergeben

<script type="text/x-magento-init">
{
    "*": {
        "Magento_Ui/js/core/app": {
            "components": {
                "example-scope": {
                    "component": "VENDOR_MODULE/js/knockout-example",
                    "exampleMessage": "<?= __('Hello Magento Stack Exchange!') ?>"
                }
            }
        }
    }
}
</script>

<div data-bind="scope: 'example-scope'">
    <h2 data-bind="text: message"></h2>
</div>

Und hier schreiben wir unser Javascript.

app/code/VENDOR/MODULE/view/frontend/web/js/knockout-example.js

define(['ko'], function(ko) {
    return function(config) {
        this.message = ko.observable(config.exampleMessage);
    }
});

 Ergebnis

Geben Sie hier die Bildbeschreibung ein

---------------------

Methode, bei der Sie HTML-Vorlagen verwenden müssen

Wenn Sie das HTML-Template-System in Magento2 / Knockout verwenden möchten (das Sie vermutlich für wichtige Arbeiten benötigen), müssen Sie im Vergleich zu meiner vereinfachten Antwort (unten) einige Änderungen vornehmen.

Wenn Sie die Vorlagenfunktionalität nicht benötigen, scrollen Sie nach unten zu meiner alten vereinfachten Antwort.

Die Dateien, die ich für dieses Beispiel verwende, sind:

  • app/design/frontend/VENDOR/THEME/Magento_Cms/templates/knockout.phtml
  • app/design/frontend/VENDOR/THEME/Magento_Cms/web/js/knockout-example.js
  • app/design/frontend/VENDOR/THEME/Magento_Cms/web/template/test.html

Die PHTML-Vorlagendatei

Die einzige Änderung an unserer PHTML-Vorlage ist der Aufruf der getTemplate()Funktion:

<script type="text/x-magento-init">
{
    "*": {
        "Magento_Ui/js/core/app": {
            "components": {
                "example-scope": {
                    "component": "Magento_Cms/js/knockout-example",
                    "exampleMessage": "<?= __('Hello Magento Stack Exchange!') ?>"
                }
            }
        }
    }
}
</script>

<div data-bind="scope: 'example-scope'">
    <h2 data-bind="text: message"></h2>
    <!-- ko template: getTemplate() --><!-- /ko -->
</div>

Die JS-Datei (Komponentendatei)

Es gibt einige Änderungen, die Sie an der JS-Datei vornehmen müssen. Ich werde diese unten detailliert beschreiben.

define(['ko', 'uiComponent'], function(ko, Component) {
    'use strict';

    return Component.extend({
        defaults: {
            exampleMessage: 'Hello?',
            template: 'Magento_Cms/test'
        },

        initialize: function() {
            this._super();
            console.log(this.exampleMessage);
            this.message = ko.observable(this.exampleMessage);
        }
    });
});

1 - Ihre Rückgabefunktion muss jetzt das uiComponent-Modul erweitern:

return Component.extend({
    ...
});

2 - Sie müssen eine initializeFunktion hinzufügen und aufrufen this._super(). this._super()ruft die Funktion der übergeordneten Komponente mit demselben Namen auf. So in diesem Fall ich denke , es nennen wird initializevon uiComponent.

initialize: function() {
    this._super();
    ...
}.

3 - Optional - Sie können hier auch einige Standardeinstellungen für Ihre Komponente festlegen. Ich denke, dies ist eine gute Vorgehensweise, da die Arbeit mit Ihrer Komponente einfach ist. Wenn Sie es wiederverwenden, können Sie entweder die Standardeinstellungen beibehalten oder, wenn Sie es anpassen möchten, mit neuen Argumenten aufrufen, ohne die Komponente zu ändern.

Zum Beispiel, wenn Sie auf Ausfälle im JS aussehen setzt es exampleMessageauf 'Hello?'noch die Seite gerendert wird , den Text als Hello Magento Stack Exchange!. Dies liegt daran, dass ich exampleMessagedie PHTML-Datei überschrieben habe, als ich die Komponente aufgerufen habe.

Die HTML-Vorlage

Ich muss mich noch umsehen und sehen, wozu die HTML-Vorlagen in der Lage sind. Ich gehe davon aus, dass die in der Knockout JS-Dokumentation erwähnten Funktionen hier verwendet werden können, um sie ziemlich flexibel zu machen.

Ich habe gerade einen Lorem-Ipsum-Text hinzugefügt. Ich werde wahrscheinlich eine weitere Frage / Antwort geben, sobald ich herausgefunden habe, was die HTML-Vorlagen können.

Lorem ipsum dolor sit amet, consectetur adipisicing elit. Asperiores assumenda beatae blanditiis culpa cupiditate doloremque, expedita ipsum iure magni minima modi molestiae nulla optio porro ratione reiciendis repellat soluta voluptatum!

Das Ergebnis und das Überschreiben der Standardeinstellungen

Wie bereits erwähnt, können Sie sehen, dass ich exampleMessagedie Vorlage überschrieben habe . Sie können sehen, dass sie beim Lesen des Textes funktioniert Hello Magento Stack Exchange.

Geben Sie hier die Bildbeschreibung ein

Wenn ich die Überschreibung in der Vorlagendatei entferne, exampleMessagewird auf die Standardeinstellung von zurückgesetzt Hello?. Ich musste löschen var/view_preprocessedund pub/static/frontendnachdem ich dies geändert hatte. Ich nehme an, Magento hat den Wert zwischengespeichert.

Geben Sie hier die Bildbeschreibung ein


Dies wird in Magento2.1
Venkat

@Venkat - Meinst du, du kannst Knockout jetzt einfach verwenden, ohne den Knoten reinigen zu müssen? Oder dass mein Fix in 2.1 funktioniert?
Ben Crook

Ihr Fix wird in 2.1 funktionieren?
Venkat

Für mich funktioniert Bindungen, aber es wird ein Referenzfehler für die erste Eingabe der Datenbindung angezeigt
Venkat

Ich denke schon, da sich KnockoutJS seit 2.0.X nicht viel geändert zu haben scheint - ich habe es in 2.1 allerdings nicht ausprobiert, daher bin ich mir nicht 100% sicher. Stellen Sie außerdem sicher, dass Sie einige gründliche Tests durchführen, da ich nicht sicher bin, ob dies die beste Methode ist. Es ist jedoch die einzige, die ich finden kann.
Ben Crook

Durch die Nutzung unserer Website bestätigen Sie, dass Sie unsere Cookie-Richtlinie und Datenschutzrichtlinie gelesen und verstanden haben.
Licensed under cc by-sa 3.0 with attribution required.