2

I`m trying to load a custom script after a custom-template for minicart items is rendered.

I created a javascript file vendor\module\view\frontend\web\js\test.js:

define('jquery', function($) {

    alert('Here');

});

and added it to my requirejs-config.js:

var config = {
    map: {
        '*': {
            'Magento_Checkout/template/minicart/item/default.html':
                'Vendor_Module/template/minicart/item/default.html',
            test: 'Vendor_Module/js/test'
        }
    }
};

No I try to run it after the rendering in my default.html with:

<div class="test" afterRender="test"></div>

But the console just outputs:

test is not defined

I really would appreciate any help on this. Why is the script not loaded?

For clarification: Vendor and Module are of course placeholders here.

4
  • Did you try to change return type of your test class to the function? Like : return function () { alert(''Here) } . As I can see in the magento files it's trying to use return value as a callback. Mar 12, 2020 at 9:35
  • I edited my test.js to this: define('jquery', return function () { alert('Here') } ); - makes no difference
    – Mario
    Mar 12, 2020 at 9:54
  • Can you share your HTML please.
    – Ben Crook
    Mar 12, 2020 at 10:54
  • I put it here: jsfiddle.net/kbv65m2g
    – Mario
    Mar 12, 2020 at 11:02

1 Answer 1

7

The afterRender method calls the specified method (test) of your component. So for your case you must define the test method inside the minicart component. You must add a mixin for the vendor/magento/module-checkout/view/frontend/web/js/view/minicart.js and add the test method or completely change the renderer component to define a new method. Here is simple example with overwriting a renderer component in custom module:

Here is complete code of example on GitHub.

Set custom template and custom component where we can define out test method:

app/code/MageWorx/UpdateMinicart/view/frontend/layout/checkout_cart_sidebar_item_renderers.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>
        <referenceBlock name="minicart">
            <arguments>
                <argument name="jsLayout" xsi:type="array">
                    <item name="components" xsi:type="array">
                        <item name="minicart_content" xsi:type="array">
                            <item name="children" xsi:type="array">
                                <item name="item.renderer" xsi:type="array">
                                    <item name="config" xsi:type="array">
                                        <item name="component" xsi:type="string">MageWorx_UpdateMinicart/js/minicart/item/default</item>
                                        <item name="template" xsi:type="string">MageWorx_UpdateMinicart/minicart/item/default</item>
                                    </item>
                                </item>
                            </item>
                        </item>
                    </item>
                </argument>
            </arguments>
        </referenceBlock>
    </body>
</page>

Update regular template (add a custom div with afterRender binding):

app/code/MageWorx/UpdateMinicart/view/frontend/web/template/minicart/item/default.html

<li class="item product product-item" data-role="product-item">
    <div class="test" afterRender="$parent.test"></div>
    <div class="product">
        <!-- ko if: product_has_url -->
        <a data-bind="attr: {href: product_url, title: product_name}" tabindex="-1" class="product-item-photo">
            <!-- ko foreach: $parent.getRegion('itemImage') -->
            <!-- ko template: {name: getTemplate(), data: item.product_image} --><!-- /ko -->
            <!-- /ko -->
        </a>
        <!-- /ko -->
        <!-- ko ifnot: product_has_url -->
        <span class="product-item-photo">
            <!-- ko foreach: $parent.getRegion('itemImage') -->
            <!-- ko template: {name: getTemplate(), data: item.product_image} --><!-- /ko -->
            <!-- /ko -->
        </span>
        <!-- /ko -->

        <div class="product-item-details">
            <strong class="product-item-name">
                <!-- ko if: product_has_url -->
                <a data-bind="attr: {href: product_url}, html: product_name"></a>
                <!-- /ko -->
                <!-- ko ifnot: product_has_url -->
                <!-- ko text: product_name --><!-- /ko -->
                <!-- /ko -->
            </strong>

            <!-- ko if: options.length -->
            <div class="product options" data-mage-init='{"collapsible":{"openedState": "active", "saveState": false}}'>
                <span data-role="title" class="toggle"><!-- ko i18n: 'See Details' --><!-- /ko --></span>

                <div data-role="content" class="content">
                    <strong class="subtitle"><!-- ko i18n: 'Options Details' --><!-- /ko --></strong>
                    <dl class="product options list">
                        <!-- ko foreach: { data: options, as: 'option' } -->
                        <dt class="label"><!-- ko text: option.label --><!-- /ko --></dt>
                        <dd class="values">
                            <!-- ko if: Array.isArray(option.value) -->
                            <span data-bind="html: option.value.join('<br>')"></span>
                            <!-- /ko -->
                            <!-- ko ifnot: Array.isArray(option.value) -->
                            <span data-bind="text: option.value"></span>
                            <!-- /ko -->
                        </dd>
                        <!-- /ko -->
                    </dl>
                </div>
            </div>
            <!-- /ko -->

            <div class="product-item-pricing">
                <!-- ko if: canApplyMsrp -->

                <div class="details-map">
                    <span class="label" data-bind="i18n: 'Price'"></span>
                    <span class="value" data-bind="i18n: 'See price before order confirmation.'"></span>
                </div>
                <!-- /ko -->
                <!-- ko ifnot: canApplyMsrp -->
                <!-- ko foreach: $parent.getRegion('priceSidebar') -->
                <!-- ko template: {name: getTemplate(), data: item.product_price, as: 'price'} --><!-- /ko -->
                <!-- /ko -->
                <!-- /ko -->

                <div class="details-qty qty">
                    <label class="label" data-bind="i18n: 'Qty', attr: {
                           for: 'cart-item-'+item_id+'-qty'}"></label>
                    <input data-bind="attr: {
                           id: 'cart-item-'+item_id+'-qty',
                           'data-cart-item': item_id,
                           'data-item-qty': qty,
                           'data-cart-item-id': product_sku
                           }, value: qty"
                           type="number"
                           size="4"
                           class="item-qty cart-item-qty">
                    <button data-bind="attr: {
                           id: 'update-cart-item-'+item_id,
                           'data-cart-item': item_id,
                           title: $t('Update')
                           }"
                            class="update-cart-item"
                            style="display: none">
                        <span data-bind="i18n: 'Update'"></span>
                    </button>
                </div>
            </div>

            <div class="product actions">
                <!-- ko if: is_visible_in_site_visibility -->
                <div class="primary">
                    <a data-bind="attr: {href: configure_url, title: $t('Edit item')}" class="action edit">
                        <span data-bind="i18n: 'Edit'"></span>
                    </a>
                </div>
                <!-- /ko -->
                <div class="secondary">
                    <a href="#" data-bind="attr: {'data-cart-item': item_id, title: $t('Remove item')}"
                       class="action delete">
                        <span data-bind="i18n: 'Remove'"></span>
                    </a>
                </div>
            </div>
        </div>
    </div>
</li>

Define the component having test function (we just logging a dummy string inside):

app/code/MageWorx/UpdateMinicart/view/frontend/web/js/minicart/item/default.js

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

        return Component.extend({
            test: function () {
                console.log('HERE I\'M');
                // $('#test').doSomething();
            }
        });
    }
);

Here is output on the frontend with 2 items added in minicart:

example output

Here is some clarification for "why test is not defined" error from your example:

When you put the test method in the afterRender binding inside template, the ko calling some anonymous function which binds an actual context and trying to call method you pass:

(function anonymous($context,$element
) {
with($context){with($data||{}){return{'afterRender':function(){return test }}}}
})

An actual context in that case (item renderer in cart) is Window which has no method test:

context example

The $parent for this context is our component:

parent context example view

Another available parents could be seen using the $parents keyword and we can access them using $parents[n] call inside the afterRender binding. The $data variable has all data about current cart item:

parents and $data

6
  • Thanks, I'll try that. I will set the checkmark to your answer, if it works ;-)
    – Mario
    Mar 12, 2020 at 11:10
  • @Mario Sure, I've added some more clarifications to my answer with result of debugging on my local env. Mar 12, 2020 at 11:34
  • Ok, seems to run :) Is there anything I can do to run jquery inside the test-function? I tried to add 'jquery' after 'uiComponent' in my default.js - but that doesnt seem to be the correct way. I wonder how to add the "required" stuff....
    – Mario
    Mar 12, 2020 at 12:09
  • @Mario just add jquery inside the define first argument (array) and alias for it inside the arguments of second argument. Or just check updated answer, it will be more clear. Mar 12, 2020 at 12:23
  • Awesome! Thank you very much sir!
    – Mario
    Mar 12, 2020 at 12:27

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.