Magento 2 Knockout JS Dependent Dropdowns Guide

knockoutjsmagento2

How can I create a pair of dropdowns such that when one is selected, the options for the other one are updated?
The values for options for both dropdowns are coming from PHP.

I have absolutely no clue about knockout js. Any help would be appreciated.

Thanks

Best Answer

In phtml template file add following code:

<div id="dependable-dropdown" data-bind="scope: 'dependableDropdown'">
    <select data-bind="options: availableOptions,
                       optionsText: 'label',
                       optionsValue: 'value',
                       optionsCaption: 'Choose...', value: selectedItem" name="dropdown1"></select>
    <select data-bind="options: availableOptions2,
                       optionsText: 'label',
                       optionsValue: 'value',
                       optionsCaption: 'Choose...', " name="dropdown2"></select>
</div>
<script type="text/x-magento-init">
{
    "#dependable-dropdown": {
        "Magento_Ui/js/core/app": {
           "components": {
                "dependableDropdown": {
                    "component": "SR_MagentoCommunity/js/dropdown",
                    "config": <?= $block->getConfigData() ?>
                }
            }
        }
    }
}
</script>

Create js

app/code/SR/MagentoCommunity/view/frontend/web/js/dropdown.js

define([
    'jquery',
    'uiComponent',
    'ko',
    'underscore'
], function (
    $,
    Component,
    ko,
    _
) {
    'use strict';

    return Component.extend({
        availableOptions: ko.observableArray([]),
        availableOptions2: ko.observableArray([]),
        selectedItem: ko.observable(),
        /**
         * Init component
         */
        initialize: function (config) {
            this._super();
            var self = this;
            _.each(config.dropdown, function (dropdownValue, key) {
                var value = dropdownValue.value;
                var label = dropdownValue.label;
                var option = {
                    'value': value,
                    'label': label
                };
                self.availableOptions.push(option);
            });
            self.selectedItem.subscribe(function(value) {
                if (value) {
                    self.availableOptions2([]);
                    _.each(config.dropdown, function (dropdownValue, key) {
                        if (dropdownValue.value == value) {
                            _.each(dropdownValue.dropdown, function (dropdown1Value) {
                                var value = dropdown1Value.value;
                                var label = dropdown1Value.label;
                                var option = {
                                    'value': value,
                                    'label': label
                                };
                                self.availableOptions2.push(option);
                            });
                        }
                    });
                } else {
                    self.availableOptions2([]);
                }
            });
            return this;
        }
    });
});

In block class:

app/code/SR/MagentoCommunity/Block/Page.php

<?php
namespace SR\MagentoCommunity\Block;

use Magento\Framework\View\Element\Template;
use Magento\Framework\Serialize\SerializerInterface;

class Page extends Template
{
    /**
     * @var SerializerInterface
     */
    protected $serializer;

    /**
     * Page constructor.
     *
     * @param Template\Context $context
     * @param SerializerInterface $serializer
     * @param array $data
     */
    public function __construct(
        Template\Context $context,
        SerializerInterface $serializer,
        array $data = []
    ) {
        $this->serializer = $serializer;
        parent::__construct($context, $data);
    }
    public function getConfigData()
    {
        $dropdown = [
            [
                'label' => 'Option 1',
                'value' => 'option1',
                'dropdown' => [
                    [
                        'label' => 'Option 11',
                        'value' => 'option11'
                    ],
                    [
                        'label' => 'Option 12',
                        'value' => 'option12'
                    ]
                ]
            ],
            [
                'label' => 'Option 2',
                'value' => 'option2',
                'dropdown' => [
                    [
                        'label' => 'Option 21',
                        'value' => 'option21'
                    ]
                ]
            ],
            [
                'label' => 'Option 3',
                'value' => 'option3',
                'dropdown' => [
                    [
                        'label' => 'Option 31',
                        'value' => 'option31'
                    ],
                    [
                        'label' => 'Option 32',
                        'value' => 'option32'
                    ]
                ]
            ]
        ];
        return $this->serializer->serialize(['dropdown' => $dropdown]);
    }
}
Related Topic