5

I'm trying to trigger custom event whenever Magento displays the product swatches in category view.

It looks like Magento uses ajax to load these swatches, they are not displayed on page load, they "pop" after a few moments. I need to add some custom JavaScript code after these swatches are actually displayed. So I thought the best way will be to trigger custom event just after Magento finishes to render the swatches. But I'm not sure how to do this correctly in Magento 2.

enter image description here

What I want to do is to trigger a custom event $(document).trigger('swatches-visible'); when a block of swatches is finally displayed on the page.

And then, an event handler will execute a function:

$(document).on('swatches-visible', function() { 
    doSomething(); 
});

That function doSomething() is already added via RequireJS in one of the template files:

<script type="text/javascript">
    requirejs(['jquery'], function(jQuery) {
        function doSomething()
        {
            // Here make some layout changes of the products list...
        }
    });
</script>
10
  • Are you loading your script via RequireJS? I ask this as you can tell Require to only load a script when a certain element has been rendered with x-magento-ini. See this section of the dev docs for more info - devdocs.magento.com/guides/v2.0/javascript-dev-guide/javascript/…
    – Ben Crook
    Oct 3, 2016 at 12:30
  • @Ben-Space48 I want to trigger custom event $(document).trigger('swatches-visible') when a block of swatches is finally displayed. And then, an event handler will execute a function: $(document).on('swatches-visible', function(e) { doSomething(); }); That function doSomething() is already added via RequireJS in one of the template files. What you proposed sounds like a good solution but I'm not sure how to use it in my case. Isn't
    – zitix
    Oct 3, 2016 at 15:08
  • Isn't data-mage-init executed only on page load? Note that the blocks of swatches for all products, e.g. <div class="swatch-opt-1822">...</div>, are displayed with a delay, not instantly on page load.
    – zitix
    Oct 3, 2016 at 15:20
  • I know data-mage-init is, x-magento-init is different although I'm not sure if that is also only on page load (the dev docs don't mention). If it is page load then the only other method I can think of is to initialise the JS inside the swatch template. Require works in templates to so I don't see why that wouldn't work.
    – Ben Crook
    Oct 3, 2016 at 15:33
  • Although JS inside a template isn't the cleanest method :(
    – Ben Crook
    Oct 3, 2016 at 15:34

3 Answers 3

12

I used the event 'swatch.initialized' to fire a function after swatches are loaded in the product page:

$(document).on('swatch.initialized', function() {
  // do something
})

The event is triggered in Magento_Swatches/js/swatch-renderer.js

$(this.element).trigger('swatch.initialized');
2

Try With This one.

 <script type="text/javascript">
        require(['jquery','Magento_Swatches/js/swatch-renderer'],function($,swatch){
                $(document).on('swatch.initialized', function() {
                   function doSomething()
                     {
                         // Here make some layout changes of the products list...
                     }
                });
       </script>  
2

While @Guillem Lorman's answer is good. A more general approach, which gives you more control, is to use mixins. This allows you to trigger your script before/after a certain function has completed. Like this:

app/code/Namespace/ModuleName/view/frontend/requirejs-config.js

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

Then go through the code of swatch-renderer.js to see before/after which function you'd like to trigger your code. E.g. to plug into _RenderSwatchSelect you could do the following:

app/code/Namespace/ModuleName/viewfrontend/web/js/swatch-renderer-mixin.js

define([
    'jquery'
], function (
    $
) {
    'use strict';

    return function (widget) {
        $.widget('mage.SwatchRenderer', widget, {

            // Pay attention to parameters in the original function.
            _RenderSwatchSelect: function(config, chooseText) {
                // Trigger original function.
                this._super(config, chooseText);

                console.log('Yeah!');

                /**
                 * If you want to trigger your function before the original function, 
                 * you'd place this.super(config, chooseText) here.
                 */
            },
        });

        return $.mage.SwatchRenderer;
    }
});
1
  • Exactly something that I was looking for. gives much more access than just initialise event. Thanks Sep 25, 2020 at 11:28

Your Answer

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

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