Cara menggunakan Knockout JS dalam Magento 2

12

Masalahku:

Saya mencoba untuk menulis aplikasi Knockout JS kecil di dalam Magento 2, saya berjuang untuk menginisialisasi aplikasi seperti ketika saya menggunakannya ko.applyBindings(AppViewModel, document.getElementById("koTest"));merusak Knockout yang digunakan oleh Magento dan melempar kesalahan ini:

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

Saya menduga itu karena:

Saya menduga ini karena Magento 2 sudah digunakan di ko.applyBindings()dalam app/code/Magento/Ui/view/base/web/js/lib/knockout/bootstrap.js. Dan karena itu tidak menentukan node saya tidak bisa menggunakan ko.applyBindingslagi.

Jika saya tidak menggunakan ko.applyBindings(AppViewModel, document.getElementById("koTest"))kode saya maka aplikasi saya tidak diinisialisasi.

Ini membuat saya berpikir saya perlu entah bagaimana menggunakan ko.applyBindings()di knockout / bootstrap.js tapi saya tidak tahu caranya, ada yang bisa membantu? Saya memiliki sedikit pengalaman dengan Knockout.

Kode Saya

<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
sumber
1
Ada tutorial di sini: inchoo.net/magento-2/knockout-js-in-magento-2
Aaron Allen

Jawaban:

23

Metode sederhana di mana Anda TIDAK perlu menggunakan templat html

Berkat Vinai Kopp, saya akhirnya mendapat jawaban untuk ini, itu jauh lebih sederhana daripada solusi hacky saya sebelumnya (saya sedang membersihkan node). Yang perlu Anda lakukan adalah mendefinisikan 'ko'sebagai ketergantungan dan menambahkan kode Anda di dalam fungsi kembali.

Di bawah ini adalah contoh sederhana yang menerjemahkan beberapa teks yang dikirimkan melalui JSON.

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

Di sini kami memberi tahu Magento ruang lingkup komponen kami (ini harus cocok data-bind: "scope: 'example-scope'"dan meneruskan data tambahan apa pun. Ini bisa menjadi basis URL, pesan sederhana, cukup banyak apa pun yang Anda inginkan. Saya telah mengirimkan string (PHP echo) sebagai contoh

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

Dan di sini kita menulis Javascript kita.

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

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

 Hasil

masukkan deskripsi gambar di sini

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

Metode di mana Anda DO perlu menggunakan templat HTML

Jika Anda ingin menggunakan sistem templating HTML dalam Magento2 / Knockout (yang saya duga Anda perlukan untuk pekerjaan yang signifikan) ada beberapa perubahan yang perlu Anda lakukan dibandingkan dengan jawaban saya yang disederhanakan (di bawah).

Jika Anda tidak memerlukan fungsionalitas templat, gulir ke bawah ke jawaban sederhana saya yang lama.

File yang saya gunakan untuk contoh ini adalah:

  • 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

File template PHTML

Satu-satunya perubahan pada templat PHTML kami adalah panggilan ke getTemplate()fungsi:

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

File JS (komponen)

Ada beberapa perubahan yang perlu Anda lakukan pada file JS, saya akan menjelaskannya di bawah ini.

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 - Fungsi pengembalian Anda sekarang perlu memperluas modul uiComponent:

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

2 - Anda perlu menambahkan initializefungsi dan panggilan this._super(). this._super()akan memanggil fungsi komponen induk dengan nama yang sama. Jadi dalam hal ini saya pikir itu akan memanggil initializedari uiComponent.

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

3 - Opsional - Anda juga dapat menetapkan beberapa default untuk komponen Anda di sini, saya pikir ini adalah praktik yang baik untuk diikuti karena membuat komponen Anda mudah untuk dikerjakan. Ketika Anda menggunakannya kembali, Anda dapat menyimpan default atau jika Anda ingin menyesuaikannya Anda bisa menyebutnya dengan argumen baru tanpa mengubah komponen.

Misalnya, jika Anda melihat default di JS yang ditetapkan exampleMessageuntuk 'Hello?'halaman belum rendering teks sebagai Hello Magento Stack Exchange!. Ini karena saya telah ditimpa exampleMessagedalam file PHTML ketika saya memanggil komponen.

Template HTML

Saya masih mencari-cari dan melihat apa yang bisa templat HTML, saya kira fitur yang disebutkan pada dokumentasi Knockout JS dapat digunakan di sini membuat mereka cukup fleksibel.

Saya baru saja menambahkan beberapa teks lorem ipsum untuk saat ini, saya kemungkinan akan memberikan pertanyaan / jawaban lain setelah saya mengetahui apa yang dapat dilakukan templat 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!

Hasilnya, dan menimpa default

Seperti disebutkan sebelumnya Anda dapat melihat bahwa saya telah ditimpa exampleMessagedalam template, Anda dapat melihatnya berfungsi saat teks dibaca Hello Magento Stack Exchange.

masukkan deskripsi gambar di sini

Jika saya menghapus override dalam file template exampleMessageakan kembali ke defaultnya Hello?. Saya memang perlu menghapus var/view_preprocesseddan pub/static/frontendsetelah mengubah ini. Saya kira Magento telah menyimpan nilai.

masukkan deskripsi gambar di sini

Ben Crook
sumber
Ini akan bekerja di Magento2.1
Venkat
@ Vikkat - Maksud Anda sekarang Anda dapat dengan mudah menggunakan Knockout tanpa harus membersihkan simpul? Atau perbaikan saya berhasil di 2.1?
Ben Crook
Perbaikan Anda akan bekerja di 2.1?
Venkat
Bagi saya pengikatan bekerja tetapi mendapatkan kesalahan referensi untuk pengikatan data input pertama
Venkat
Saya pikir jadi KnockoutJS sepertinya tidak banyak berubah sejak 2.0.X - Saya belum mencobanya di 2.1, jadi saya tidak 100% yakin. Juga pastikan Anda melakukan pengujian menyeluruh karena saya tidak yakin apakah ini adalah metode terbaik, itu satu-satunya yang dapat saya temukan.
Ben Crook