1

For example I want to change some options of minicart dialog initialization. So I need to change minicart template (override this template in custom theme/module). Is there a way to change minicart dialog init options without overriding a template?

  • Your question is not clear to me. Can you provide more info? – Khoa TruongDinh May 31 '18 at 11:20
  • @KhoaTruongDinh thanks for replying. I added an example – Denys Belevtsov May 31 '18 at 14:09
1

Add "Js Init Modifier" in your custom module.

Your/Module/view/frontend/layout/default.xml

<?xml version="1.0"?>
<page xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="urn:magento:framework:View/Layout/etc/page_configuration.xsd">
    <body>
        <referenceContainer name="before.body.end">
            <block name="js.init.modifier" template="Your_Module::js-init-modifier.phtml" before="-"/>
        </referenceContainer>
    </body>
</page>

Your/Module/view/frontend/templates/js-init-modifier.phtml

<?php
/**
 * Changes JS component init options before component initialized
 *
 * @var \Magento\Framework\View\Element\Template $block
 */
?>

<script>
jsInitModifier = {
    BLOCK_TYPE_ATTR: 1,
    BLOCK_TYPE_SCRIPT_TAG: 2,

    /**
     * Changes JS component init options before component initialized
     *
     * @param target String
     * @param options Object
     *
     * @return void
     */
    setJsInitBlockOptions: function (target, options) {
        var initBlocks, initBlock;
        var initBlockType = this.getInitBlockType(target);

        if (initBlockType === this.BLOCK_TYPE_ATTR) {
            initBlock = document.querySelector(target);
        } else if (initBlockType === this.BLOCK_TYPE_SCRIPT_TAG) {
            initBlocks = document.querySelectorAll('[type="text/x-magento-init"]');
            initBlock = this.getInitBlockByKeyword(initBlocks, target);
        }

        if (initBlock === null) {
            console.error('jsInitModifier: cannot find init block "' + target + '"');
            return;
        }

        if (initBlockType === this.BLOCK_TYPE_ATTR) {
            this.setInitBlockOptionsAsAttr(initBlock, options);
        } else if (initBlockType === this.BLOCK_TYPE_SCRIPT_TAG) {
            this.setInitBlockOptionsInScriptTag(initBlock, options);
        }
    },

    /**
     * @param target String
     *
     * @return {Number}
     */
    getInitBlockType: function (target) {
        try {
            var s = document.querySelector(target);

            if (s !== null) {
                return this.BLOCK_TYPE_ATTR;
            } else {
                return this.BLOCK_TYPE_SCRIPT_TAG;
            }
        } catch (e) {
            return this.BLOCK_TYPE_SCRIPT_TAG;
        }
    },

    /**
     * @param initBlocks Array
     * @param keyword string
     *
     * @return {Element|null}
     */
    getInitBlockByKeyword: function (initBlocks, keyword) {
        var block = null;

        initBlocks.forEach(function (initBlock) {
            if (initBlock.innerHTML.indexOf(keyword) !== -1) {
                block = initBlock;
            }
        });

        return block;
    },

    /**
     * @param jsonOptionsAsString String
     *
     * @return {Object}
     */
    getInitBlockOptionsObject: function (jsonOptionsAsString) {
        return JSON.parse(jsonOptionsAsString);
    },

    /**
     * @param initBlock Element
     * @param initBlockOptionsCustom Object
     *
     * @return {void}
     */
    setInitBlockOptionsAsAttr: function (initBlock, initBlockOptionsCustom) {
        var initBlockOptionsInitial = this.getInitBlockOptionsObject(initBlock.dataset.mageInit);
        var customInitOptions = this.mergeObjectsRecursive(initBlockOptionsInitial, initBlockOptionsCustom);

        initBlock.dataset.mageInit = JSON.stringify(customInitOptions);
    },

    /**
     * @param initBlock Element
     * @param initBlockOptionsCustom Object
     *
     * @return {void}
     */
    setInitBlockOptionsInScriptTag: function (initBlock, initBlockOptionsCustom) {
        var initBlockOptionsInitial = this.getInitBlockOptionsObject(initBlock.innerHTML);
        var customInitOptions = this.mergeObjectsRecursive(initBlockOptionsInitial, initBlockOptionsCustom);

        initBlock.innerHTML = JSON.stringify(customInitOptions);
    },

    /**
     * Recursively merge properties of two objects
     *
     * @param obj1 Object
     * @param obj2 Object
     *
     * @return {Object}
     */
    mergeObjectsRecursive: function (obj1, obj2) {
        var self = this;

        for (var prop in obj2) {
            try {
                // Property in destination object set; update its value.
                if (obj2[prop].constructor === Object) {
                    obj1[prop] = self.mergeObjectsRecursive(obj1[prop], obj2[prop]);

                } else {
                    obj1[prop] = obj2[prop];
                }
            } catch (e) {
                // Property in destination object not set; create it and set its value.
                obj1[prop] = obj2[prop];
            }
        }

        return obj1;
    }
}
</script>
  1. Call "setJsInitBlockOptions()" method in you custom template.
  2. 1st arg - element selector to change "data-mage-init" attribute or any text as keyword to change "text/x-magento-init" script content
  3. 2nd arg - object with options you want to change. It will be merged with initial options

See example of using the modifier:

<script>
    (function () {
        var galleryOptions = {
            '[data-gallery-role=gallery-placeholder]': {
                'mage/gallery/gallery': {
                    'options': {
                        'thumbmargin': 15,
                        'thumbborderwidth': 1
                    }
                }
            }
        };

        jsInitModifier.setJsInitBlockOptions('mage/gallery/gallery', galleryOptions);

        var minicartOptions = {
            'dropdownDialog': {
                'triggerEvent': 'hover',
                'closeOnMouseLeave': true,
                'timeout': 0
            }
        };

        jsInitModifier.setJsInitBlockOptions('.block-minicart', minicartOptions);
    })();
</script>
| improve this answer | |

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

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