2

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

1 Answer 1

5

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]);
    }
}
6
  • Thanks! Will try it and let you know.
    – coderGeek
    Commented Jul 30, 2019 at 18:32
  • I am using <type name="Magento\Checkout\Model\CompositeConfigProvider"> <arguments> <argument name="configProviders" xsi:type="array"> <item name="distribution" xsi:type="object">Vendor\Module\Model\DefaultConfigProvider</item> </argument> </arguments> </type> and when I pass the serialized result, I get this error - Exception #0 (Exception): Warning: array_merge_recursive(): Argument #2 is not an array in /{MAGENTO_DIR}/magento/module-checkout/Model/CompositeConfigProvider.php on line 39
    – coderGeek
    Commented Jul 30, 2019 at 19:20
  • I am overriding Magento/Checkout/view/frontend/web/template/shipping-address/list.html so I don't have a phtml but list.html file and list.js file.
    – coderGeek
    Commented Jul 30, 2019 at 19:23
  • You update your question where you want this. In checkout page pass from php through CompositeConfigProvider check github.com/sohelrana09/magento2-module-delivery-date/blob/…. Then add js to your js.
    – Sohel Rana
    Commented Jul 31, 2019 at 1:17
  • Your code was great help. Thanks! Can you explain how observables and observableArrays work.
    – coderGeek
    Commented Jul 31, 2019 at 15:40

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.