Implement jQuery Click Event in Magento Knockout JS Function – Tutorial

jqueryknockoutjsmagento2

how to implement below jQuery code into knockout js, Actually I'm trying to call this function on a button click event using knockout js, but it's not working

HTML code:

<div>
    <ul class="list-group">
       <li>
        <button id="buttonid">click</button>
        Item 1
       </li>
        <li>
        <button id="buttonid">click</button>
        Item 2
       </li>
    </ul>
</div>

jQuery COde:

$('#buttonid').on("click",".list-group-item",function(e){
console.log($(this).text());
console.log(e.target.id);
});

In this code .list-group-item is the class of ul tag. Here I wanna try to get title text of li items.

please guide me to implement above jQuery function in knockout js!

Best Answer

Template

  • Removed id's since there shouldn't be more than one element on page with the same id
  • Wrapped list item text with a span since trying to output the text of the li element would also output the button text

With Magento Init Script

<div>
    <ul class="list-group" data-role="item-announcer">
        <li>
            <button data-action="announce-item">click</button>
            <span data-role="item">Item 1</span>
        </li>
        <li>
            <button data-action="announce-item">click</button>
            <span data-role="item">Item 2</span>
        </li>
    </ul>
</div>

<script type="text/x-magento-init">
    {
        "[data-role=item-announcer]": {
            "Magento_Theme/js/item-announcer": {}
        }
    }
</script>

With Data Mage Init Attribute

<div>
    <ul class="list-group" data-mage-init='{"Magento_Theme/js/item-announcer": {}}'>
        <li>
            <button data-action="announce-item">click</button>
            <span data-role="item">Item 1</span>
        </li>
        <li>
            <button data-action="announce-item">click</button>
            <span data-role="item">Item 2</span>
        </li>
    </ul>
</div>

Component

In app/design/frontend/[vendor]/[theme]/Magento_Theme/web/js/item-announcer.js:

define([
    'jquery',
    'domReady!'
], function($) {
    return function(config, element) {
        let actionSelector = '[data-action=announce-item]';
        let itemSelector = '[data-role=item]';

        $(element).on('click', actionSelector, function (e) {
            e.preventDefault();
            let item = $(this).siblings(itemSelector);
            console.log(item.text());
        });
    }
});

With Knockout Component

Template

<?php
/** @var \Magento\Framework\View\Element\Template $block */
$jsId = $block->getJsId();
$items = [
    [
        'name' => 'Item 1'
    ],
    [
        'name' => 'Item 2'
    ]
];
?>

<div data-bind="scope: 'item-announcer-<?= $jsId; ?>'">
    <ul class="list-group" data-bind="visible: isVisible()" style="display: none;">
        <!-- ko foreach: items -->
        <li>
            <button data-bind="click: $parent.announce">click</button>
            <span data-bind="text: name"></span>
        </li>
        <!-- /ko -->
    </ul>
</div>

<script type="text/x-magento-init">
    {
        "*": {
            "Magento_Ui/js/core/app": {
                "components": {
                    "item-announcer-<?= $jsId; ?>": {
                        "component": "Magento_Theme/js/item-announcer",
                        "items": <?= json_encode($items); ?>
                    }
                }
            }
        }
    }
</script>

Component

In app/design/frontend/[vendor]/[theme]/Magento_Theme/web/js/item-announcer.js:

define([
    'uiComponent'
], function(Component) {
    return Component.extend({
        defaults: {
            items: []
        },

        /**
         * @inheritdoc
         */
        initObservable: function () {
            this._super()
                .observe('items');
            return this;
        },

        /**
         * Announce Text
         *
         * @param item
         */
        announce: function (item) {
            console.log(item.name);
        },

        /**
         * Get whether component is visible
         *
         * @returns {boolean}
         */
        isVisible: function () {
            return this.items().length > 0;
        }
    });
});