Jak korzystać z Knockout JS w Magento 2

12

Mój problem:

Próbuję napisać małą aplikację Knockout JS w Magento 2, staram się zainicjować aplikację, ponieważ gdy ko.applyBindings(AppViewModel, document.getElementById("koTest"));ją używam , łamie Knockout używany przez Magento i generuje ten błąd:

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

Podejrzewam, że to z powodu:

Podejrzewam, że dzieje się tak, ponieważ Magento 2 już używa ko.applyBindings()w sobie app/code/Magento/Ui/view/base/web/js/lib/knockout/bootstrap.js. A ponieważ nie określa to węzła, którego nie mogę użyć ko.applyBindingsponownie.

Jeśli nie używam ko.applyBindings(AppViewModel, document.getElementById("koTest"))w kodzie, aplikacja się nie inicjuje.

To sprawia, że ​​myślę, że muszę jakoś użyć ko.applyBindings()pliku knockout / bootstrap.js, ale nie mam pojęcia, jak ktoś może pomóc? Mam niewielkie doświadczenie z Knockout.

Mój kod

<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>
Ben Crook
źródło
1
Tutaj jest tutorial: inchoo.net/magento-2/knockout-js-in-magento-2
Aaron Allen

Odpowiedzi:

23

Prosta metoda, w której NIE musisz używać szablonów HTML

Dzięki Vinai Kopp w końcu mam odpowiedź na to pytanie, jest to o wiele prostsze niż moje poprzednie hacky obejście (czyściłem węzły). Wszystko, co musisz zrobić, to zdefiniować 'ko'jako zależność i dodać kod do funkcji zwracającej.

Poniżej znajduje się prosty przykład, który renderuje część tekstu przekazywanego przez JSON.

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

Tutaj mówimy Magento o zakresie naszych komponentów (to musi pasować data-bind: "scope: 'example-scope'"i przekazywać wszelkie dodatkowe dane. Może to być podstawowy adres URL, prosta wiadomość, prawie wszystko, co chcesz. Podałem ciąg (echo PHP) jako przykład

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

I tutaj piszemy nasz 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);
    }
});

 Wynik

wprowadź opis zdjęcia tutaj

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

Metoda, w której musisz użyć szablonów HTML

Jeśli chcesz korzystać z systemu szablonów HTML w Magento2 / Knockout (który, jak zakładam, będziesz potrzebować do znaczących prac), musisz wprowadzić kilka zmian w porównaniu z moją uproszczoną odpowiedzią (poniżej).

Jeśli nie potrzebujesz funkcji szablonu, przewiń w dół do mojej starej uproszczonej odpowiedzi.

Pliki, których używam w tym przykładzie to:

  • 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

Plik szablonu PHTML

Jedyną zmianą w naszym szablonie PHTML jest wywołanie getTemplate()funkcji:

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

Plik JS (komponent)

Jest kilka zmian, które musisz wprowadzić w pliku JS, opiszę je szczegółowo poniżej.

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 - Twoja funkcja powrotu musi teraz rozszerzyć moduł uiComponent:

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

2 - Musisz dodać initializefunkcję i wywołać this._super(). this._super()wywoła funkcję komponentu nadrzędnego o tej samej nazwie. Tak więc w tym przypadku mogę myśleć będzie zadzwonić initializez uiComponent.

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

3 - Opcjonalne - Możesz również ustawić tutaj wartości domyślne dla swojego komponentu, uważam, że jest to dobra praktyka, ponieważ ułatwia on pracę z komponentem. Kiedy go użyjesz ponownie, możesz zachować wartości domyślne lub jeśli chcesz go dostosować, możesz wywołać go z nowymi argumentami bez zmiany komponentu.

Na przykład, jeśli spojrzysz na wartości domyślne w JS, ustawia to exampleMessagena 'Hello?'jeszcze, że strona renderuje tekst jako Hello Magento Stack Exchange!. Jest tak, ponieważ exampleMessagenadpisałem plik PHTML, kiedy wywołałem ten komponent.

Szablon HTML

Nadal muszę się rozejrzeć i zobaczyć, do czego zdolne są szablony HTML. Zakładam, że można tu użyć funkcji wymienionych w dokumentacji Knockout JS, co czyni je dość elastycznymi.

Właśnie dodałem na razie trochę tekstu lorem ipsum, zapewne udzielę innego pytania / odpowiedzi, gdy dowiem się, co mogą zrobić szablony 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!

Wynik i zastąpienie wartości domyślnych

Jak wspomniano wcześniej, możesz zobaczyć, że nadpisałem exampleMessageszablon, możesz zobaczyć, jak działa tekst Hello Magento Stack Exchange.

wprowadź opis zdjęcia tutaj

Jeśli usunę zastąpienie w pliku szablonu, exampleMessagenastąpi powrót do domyślnej wartości Hello?. Musiałem jednak usunąć var/view_preprocessedi pub/static/frontendpo zmianie. Przypuszczam, że Magento zapisał wartość w pamięci podręcznej.

wprowadź opis zdjęcia tutaj

Ben Crook
źródło
Będzie to działać w Magento 2.1
Venkat
@Venkat - Czy masz na myśli, że możesz teraz łatwo używać Knockout bez konieczności czyszczenia węzła? Czy moja poprawka działa w 2.1?
Ben Crook,
Twoja poprawka zadziała w 2.1?
Venkat
Dla mnie powiązania działają, ale pojawia się błąd odniesienia dla pierwszego powiązania danych wejściowych
Venkat
Wydaje mi się, że KnockoutJS niewiele się zmienił od wersji 2.0.X - nie wypróbowałem go jednak w wersji 2.1, więc nie jestem w 100% pewien. Upewnij się także, że wykonałeś gruntowne testy, ponieważ nie jestem pewien, czy jest to najlepsza metoda, ale jedyna, jaką mogę znaleźć.
Ben Crook,