0

I want to make the "recently viewed products" widget a Slideshow, using slick Slider.

Here's what I did so far, although this might not be the correct approach:
I copied template and viewModel into my theme:

Magento_Catalog/web/template/product/list/listing.html
magento_Catalog/web/js/product/list/listing.js

The idea is basically to use 'afterRender' to run my custom function making the widget a slider.

This is working, the code is running and successfully making the widget a slider.
The problem ist, that every item in the product-list is becoming a new row on the slideshow instead of being added to the existing one. HTML Result:

<ol class="product-items product-slider recently-viewed slick-initialized slick-slider" data-bind="afterRender: function (t) {addSlider(t);}">
    <div class="slick-list draggable" data-repeat-index="0">
        <div class="slick-track">
            <li class="product-item slick-slide slick-current slick-active" data-slick-index="0" tabindex="0">
                <div class="product-item-info">Product Item HTML Code here]</div>
            </li>
        </div>
    </div>
    <div class="slick-list draggable" data-repeat-index="1">
        <div class="slick-track">
            <li class="product-item slick-slide slick-current slick-active" data-slick-index="0" tabindex="0">
                <div class="product-item-info">[Product Item HTML Code here]</div>
            </li>
        </div>
    </div>
</ol>

expected output (taken from another product slider that's not a uiCOmponent) would be:

<ol class="products list items product-items product-slider slick-initialized slick-slider">
    <div class="slick-list draggable">
        <div class="slick-track">
            <li class="item product product-item slick-slide slick-current slick-active">Child HTML here</li>
            <li class="item product product-item slick-slide slick-active">Child HTML here</li>
            <li class="item product product-item slick-slide slick-active">Child HTML here</li>
        </div>
    </div>
</ol>

So only one .slick-list, containing one slick-track, containing all the items.

My files look like this:

listing.html:

<!--
/**
 * Copyright © Magento, Inc. All rights reserved.
 * See COPYING.txt for license details.
 */
-->
<div if="hasData()"
     class="block" css="additionalClasses">
    <div class="block-title">
        <strong role="heading"
                aria-level="2"
                text="label"/>
    </div>
    <div class="block-content">
        <div css="'products-' + displayMode">
            <ol class="product-items product-slider recently-viewed" afterRender="function (t) {addSlider(t);}">
                <li class="product-item" repeat="foreach: filteredRows, item: '$row'">
                    <div class="product-item-info">
                        <fastForEach args="data: getRegion('general-area'), as: '$col'" >
                            <render args="$col.getBody()"/>
                        </fastForEach>

                        <div class="product-item-details">
                            <fastForEach args="data: getRegion('details-area'), as: '$col'" >
                                <render args="$col.getBody()"/>
                            </fastForEach>

                            <div if="regionHasElements('action-primary-area') || regionHasElements('action-secondary-area')"
                                 class="product-item-actions">
                                <div class="actions-primary" if="regionHasElements('action-primary-area')">
                                    <fastForEach args="data: getRegion('action-primary-area'), as: '$col'" >
                                        <render args="$col.getBody()"/>
                                    </fastForEach>
                                </div>

                                <div if="regionHasElements('action-secondary-area')"
                                     class="actions-secondary"
                                     data-role="add-to-links">
                                    <fastForEach args="data: getRegion('action-secondary-area'), as: '$col'" >
                                        <render args="$col.getBody()"/>
                                    </fastForEach>
                                </div>
                            </div>

                            <div if="regionHasElements('description-area')"
                                 class="product-item-description">
                                <fastForEach args="data: getRegion('description-area'), as: '$col'" >
                                    <render args="$col.getBody()"/>
                                </fastForEach>
                            </div>
                        </div>
                    </div>
                </li>
            </ol>
        </div>
    </div>
</div>

I just added afterRender to the ol.product-items

listing.js

/**
 * Copyright © Magento, Inc. All rights reserved.
 * See COPYING.txt for license details.
 */

define([
    'ko',
    'underscore',
    'Magento_Ui/js/grid/listing',
    //I added those two:
    'jquery',
    'slick'
], function (ko, _, Listing, $) {
    'use strict';

    return Listing.extend({
        defaults: {
            additionalClasses: '',
            filteredRows: {},
            limit: 5,
            listens: {
                elems: 'filterRowsFromCache',
                '${ $.provider }:data.items': 'filterRowsFromServer'
            }
        },
        
        //Magento functions here
        
        //Added this function
        /**
         *
         * @param target
         */
        addSlider: function (target) {
            $(target).slick({
                dots: false,
                infinite: false,
                speed: 300,
                slidesToShow: 5,
                slidesToScroll: 1,
                //variableWidth: true,
                responsive: [
                    {
                        breakpoint: 1200,
                        settings: {
                            slidesToShow: 4
                        }
                    },
                    {
                        breakpoint: 900,
                        settings: {
                            slidesToShow: 3
                        }
                    },
                    {
                        breakpoint: 580,
                        settings: {
                            slidesToShow: 2,
                            arrows: false
                        }
                    },
                    {
                        breakpoint: 380,
                        settings: {
                            slidesToShow: 1,
                            arrows:false
                        }
                    }
                ]
            });
        }
    });
});

How can I fix this?

Update:
What I noticed debugging the code, if I did it correctly:
I set a breakpoint at this call in my addSlider function:

$(target).slick({

the code stops there only once.
When I inspect target at this point it has only one child Item.
maybe this causes the problem
But I don't understand it, I was thinking afterRender should fire after everything is being rendered, or every time a new child is being added, not just once in the middle of everything.

If I see this correctly I am back to beginning with the question:
How can I execute JS(jQuery) after the uiComponent has fully rendered.
Talking about initial rendering at least, I do understand the concept of data-binds to dynamically update the content but this is not really a concern in this case, since the recently viewed list doesn't update as long as the customer stays on one page.

0

1 Answer 1

0

It looks like the problem is slick's use of divs, there is an option to change this to use li which may solve your problem.

$('.slicker').slick({
  slide: 'li'
});

Whilst it is an old answer on https://stackoverflow.com/questions/24056855/using-slick-to-create-a-carousel-from-li-elements looking at the code that option still exists.

1
  • Thanks for the answer. I just tested it, it doesnt work unfortunately. Also: the slide itself already is a <li> already, the problem is just that it's wrapped in a seperate slick list for every item, instead of only one list overall.
    – Chaz
    Commented Jul 30, 2021 at 13:38

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