Come usare Knockout JS in Magento 2


12

Il mio problema:

Sto tentando di scrivere una piccola app Knockout JS in Magento 2, sto lottando per inizializzare l'app poiché quando la utilizzo ko.applyBindings(AppViewModel, document.getElementById("koTest"));interrompe il Knockout utilizzato da Magento e genera questo errore:

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

Sospetto sia a causa di:

Sospetto che sia perché Magento 2 lo usa già ko.applyBindings()all'interno app/code/Magento/Ui/view/base/web/js/lib/knockout/bootstrap.js. E poiché ciò non specifica un nodo, non posso ko.applyBindingsriutilizzarlo.

Se non uso ko.applyBindings(AppViewModel, document.getElementById("koTest"))nel mio codice, la mia app non si inizializza.

Questo mi fa pensare di dover in qualche modo usare il file ko.applyBindings()knockout / bootstrap.js ma non ho idea di come, qualcuno può aiutare? Ho poca esperienza con Knockout.

Il mio codice

<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>

Risposte:


23

Metodo semplice in cui NON è necessario utilizzare modelli html

Grazie a Vinai Kopp ho finalmente avuto una risposta a questa domanda, è molto più semplice della mia precedente soluzione complicata (stavo pulendo i nodi). Tutto quello che devi fare è definire 'ko'come dipendenza e aggiungere il tuo codice all'interno di una funzione di ritorno.

Di seguito è riportato un semplice esempio che visualizza il testo trasmesso tramite JSON.

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

Qui diciamo a Magento l'ambito dei nostri componenti (questo deve corrispondere data-bind: "scope: 'example-scope'"e trasmettere eventuali dati aggiuntivi. Potrebbe essere l'URL di base, un semplice messaggio, praticamente tutto quello che vuoi. Ho passato una stringa (eco PHP) come esempio

<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>

E qui scriviamo il nostro 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);
    }
});

 Risultato

inserisci qui la descrizione dell'immagine

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

Metodo in cui è necessario utilizzare i modelli HTML

Se si desidera utilizzare il sistema di template HTML all'interno di Magento2 / Knockout (che presumo occorrerà per qualsiasi lavoro significativo), ci sono alcune modifiche che è necessario apportare rispetto alla mia risposta semplificata (di seguito).

Se non hai bisogno della funzionalità del modello, scorri verso il basso fino alla mia vecchia risposta semplificata.

I file che sto usando per questo esempio sono:

  • 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

Il file modello PHTML

L'unica modifica al nostro modello PHTML è la chiamata alla getTemplate()funzione:

<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>

Il file JS (componente)

Ci sono alcune modifiche che dovrai apportare al file JS, le spiegherò di seguito.

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 - La tua funzione di ritorno ora deve estendere il modulo uiComponent:

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

2 - È necessario aggiungere una initializefunzione e chiamare this._super(). this._super()chiamerà la funzione del componente padre con lo stesso nome. Quindi, in questo caso io penso che chiamerà initializedi uiComponent.

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

3 - Opzionale - Puoi anche impostare alcune impostazioni predefinite per il tuo componente qui, penso che questa sia una buona pratica da seguire in quanto rende il tuo componente facile da lavorare. Quando lo riutilizzi, puoi conservare le impostazioni predefinite oppure, se desideri personalizzarlo, puoi chiamarlo con nuovi argomenti senza alterare il componente.

Ad esempio, se si osservano le impostazioni predefinite in JS, questa viene impostata exampleMessagesu 'Hello?'ma la pagina sta visualizzando il testo come Hello Magento Stack Exchange!. Questo perché ho sovrascritto exampleMessagenel file PHTML quando ho chiamato il componente.

Il modello HTML

Devo ancora scavare e vedere di cosa sono capaci i template HTML, presumo che le funzioni menzionate nella documentazione di Knockout JS possano essere usate qui rendendole piuttosto flessibili.

Ho appena aggiunto del testo di lorem ipsum per ora, probabilmente fornirò un'altra domanda / risposta una volta che avrò capito cosa possono fare i modelli HTML.

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!

Il risultato e sovrascrivere i valori predefiniti

Come accennato prima puoi vedere che ho sovrascritto exampleMessageall'interno del modello, puoi vederlo funzionare mentre il testo legge Hello Magento Stack Exchange.

inserisci qui la descrizione dell'immagine

Se rimuovo l'override nel file modello exampleMessagetornerà al suo valore predefinito di Hello?. Ho dovuto cancellare var/view_preprocessede pub/static/frontenddopo averlo cambiato però. Presumo che Magento avesse memorizzato nella cache il valore.

inserisci qui la descrizione dell'immagine


Funzionerà in Magento2.1
Venkat,

@Venkat - Vuoi dire che ora puoi usare facilmente Knockout senza dover pulire il nodo? O che la mia correzione funziona in 2.1?
Ben Crook,

La tua correzione funzionerà in 2.1?
Venkat,

Per me i binding funzionano, ma si ottiene un errore di riferimento per il primo binding dei dati di input
Venkat,

Penso che KnockoutJS non sia cambiato molto dal 2.0.X, anche se non l'ho provato in 2.1, quindi non sono sicuro al 100%. Assicurati anche di fare alcuni test approfonditi poiché non sono sicuro che questo sia il metodo migliore, è l'unico che riesco a trovare però.
Ben Crook,

Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.