3

I am trying to disable a swatch, once after it has been selected. So it should not be deselected...

How to do it in Magento2.2.x ?

1
  • I improved my answer slightly as was trying to figure out something about mixins hope this helps.
    – harri
    Commented Apr 10, 2018 at 8:30

3 Answers 3

2

I managed to stop the swatch being unselected by overriding part of the core swatch-renderer.js. I use Amasty's Color Swatches Pro so I made the change to the swatch-renderer.js in that module.

I copied the widget...

_OnClick: function ($this, $widget) {

and changed this section...

if ($this.hasClass('selected')) {
 // COMMENT OUT THE 3 LINES BELOW TO PREVENT TOGGLING OF CURRENT SWATCH SELECTION
    //$parent.removeAttr('option-selected').find('.selected').removeClass('selected');
    //$input.val('');
    //$label.text('');
} else {
    $parent.attr('option-selected', $this.attr('option-id')).find('.selected').removeClass('selected');
    $label.text($this.attr('option-label'));
    $input.val($this.attr('option-id'));
    $this.addClass('selected');
}
2
  • perfect @silkspin You really made my day Commented May 19, 2018 at 6:53
  • @silkspin I have implemented this solution, although now swatch remains selected but still I am getting undefined error upon selecting same selected swatch again. Can you please share a solution that image is not changed while selecting swatch?
    – nix
    Commented Jan 17, 2022 at 22:29
2

You could do this with modifications to the swatch-renderer.js. Adding a couple of lines of code to the _OnClick event within here like below will disable pointer events and drop the opacity so the user knows it's disabled:

    $this.parent().css("pointer-events","none");
    $this.parent().css("opacity","0.6");

I would prefer to do this with a mixin which wraps the original function to maintain all original functionality from the call and only minor additional functionality is added.

Create a Mixin to Overide Swatch Rendering

  1. Create a new JS file to override the default _OnClick method within swatch-renderer.js. You could put this in your theme or module. Here i have put it within a theme.

    define([
        'jquery',
        'mage/utils/wrapper'
    ], function ($, wrapper) {
        'use strict';
    
        return function(swatchRenderer){
    
            var OnClickWrapper = wrapper.wrap(swatchRenderer.prototype._OnClick, function(originalSwatchRenderer){
                var result = originalSwatchRenderer();
    
                /*Custom code start*/
                $(arguments[1][0]).parent().css({"pointer-events":"none","opacity":"0.6"});
                /*Custom code end*/
    
                return result;
            });
    
            swatchRenderer.prototype._OnClick = OnClickWrapper;
            return swatchRenderer;
        };
    });
    

app/design/frontend/ThemeVendor/ThemeName/Magento_Swatches/web/js/swatch-renderer-mixin.js

  1. Add a requirejs-config.js file to initalise the new mixin file:

    var config = {
    config: {
        mixins: {
            'Magento_Swatches/js/swatch-renderer': {
                'Magento_Swatches/js/swatch-renderer-mixin': true
            }
        }
    }
    };
    

app/design/frontend/ThemeVendor/ThemeName/Magento_Swatches/requirejs-config.js

14
  • This disabled the whole swatches. Commented Apr 16, 2018 at 11:29
  • 1
    In your situation the selector must be disabling the parent of all the swatches. Maybe try taking out .parent(). I did test this worked fine for me so should just be some minor tweaking required here.
    – harri
    Commented Apr 16, 2018 at 14:29
  • I tried that too but all the swatches is disabled, if i click the any swatch then rest of the swatches should enabled. @harri and thank you so much the response. will keep on checking for it. Commented Apr 16, 2018 at 16:18
  • Assume there is two swatches, first one is always selected when the page gets rendered and yes that is disabled now and the only option for us to select is second swatch but when i click that both is in disabled state, since because the first already have been disabled. Isn't it..?? hope u get the scenario correctly. Commented Apr 17, 2018 at 6:37
  • Ok from what i can tell then the issue seems to be that the first one is disabled as it is automatically selected on page load and you want to remove this behavior (the autmoatic selection of first swatch)? For me nothing is selected by default for swatches within Magento is this some functionality that has been added?
    – harri
    Commented Apr 17, 2018 at 11:15
0

\magento\app\code\Module\RewriteSwatches\etc\module.xml

<config xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xsi:noNamespaceSchemaLocation="urn:magento:framework:Module/etc/module.xsd">
<module name="Module_RewriteSwatches" setup_version="2.0.1">
</module>

\magento\app\code\Module\RewriteSwatches\view\frontend\requirejs-config.js

var config = {
config: {
    mixins: {
        'Magento_Swatches/js/swatch-renderer': {
            'Module_RewriteSwatches/js/swatch-renderer': true
        }
    }
}};

\magento\app\code\Module\RewriteSwatches\registration.php

<?php \Magento\Framework\Component\ComponentRegistrar::register(\Magento\Framework\Component\ComponentRegistrar::MODULE,'Module_RewriteSwatches',__DIR__);

\magento\app\code\Module\RewriteSwatches\view\frontend\web\js\swatch-renderer.js

    define([
    'jquery'
], function ($) {
    'use strict';
    return function (widget) {
        $.widget('mage.SwatchRenderer', widget, {

        /**
         * Event for swatch options
         *
         * @param {Object} $this
         * @param {Object} $widget
         * @param {String|undefined} eventName
         * @private
         */
        _OnClick: function ($this, $widget, eventName) {
            var $parent = $this.parents('.' + $widget.options.classes.attributeClass),
                $wrapper = $this.parents('.' + $widget.options.classes.attributeOptionsWrapper),
                $label = $parent.find('.' + $widget.options.classes.attributeSelectedOptionLabelClass),
                attributeId = $parent.attr('attribute-id'),
                $input = $parent.find('.' + $widget.options.classes.attributeInput);

            if ($widget.inProductList) {
                $input = $widget.productForm.find(
                    '.' + $widget.options.classes.attributeInput + '[name="super_attribute[' + attributeId + ']"]'
                );
            }

            if ($this.hasClass('disabled')) {
                return;
            }

            if ($this.hasClass('selected')) {
                //$parent.removeAttr('option-selected').find('.selected').removeClass('selected');
                //$input.val('');
                //$label.text('');
                //$this.attr('aria-checked', false);
            } else {
                $parent.attr('option-selected', $this.attr('option-id')).find('.selected').removeClass('selected');
                $label.text($this.attr('option-label'));
                $input.val($this.attr('option-id'));
                $input.attr('data-attr-name', this._getAttributeCodeById(attributeId));
                $this.addClass('selected');
                $widget._toggleCheckedAttributes($this, $wrapper);
            }

            $widget._Rebuild();

            if ($widget.element.parents($widget.options.selectorProduct)
                .find(this.options.selectorProductPrice).is(':data(mage-priceBox)')
            ) {
                $widget._UpdatePrice();
            }

            $(document).trigger('updateMsrpPriceBlock',
                [
                    parseInt($this.attr('index'), 10) + 1,
                    $widget.options.jsonConfig.optionPrices
                ]);

            $widget._loadMedia(eventName);
            $input.trigger('change');
        }
    });
    return $.mage.SwatchRenderer;
}
});

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.