1

I recently updated from Magento 2.3.1 to 2.3.2. I now get the below error on every page. It worked fine on 2.3.1. I have checked to make sure the API website key and secret keys are correct. I have switched to the Luma theme and the error still shows. This is a core module and nobody has ever touched the code. I have done the normal clear cache, compile, upgrade, and removed the static and generated folders but the error still persists.

Uncaught TypeError: Cannot read property 'nodeName' of undefined
at acceptData (jquery.js:3762)
at internalData (jquery.js:3830)
at Function._data (jquery.js:4040)
at UiClass.initCaptcha (reCaptcha.js:161)
at reCaptcha.js:196
at dispatch (jquery.js:5226)
at elemData.handle (jquery.js:4878)
at Object.trigger (jquery.js:5130)
at Object.jQuery.event.trigger (jquery-migrate.js:633)
at jquery.js:5860

3 Answers 3

5

For anyone else who runs into this issue when you upgrade. 2.3.2 adds new fields for the recaptcha and enables all of them. When I disabled the newsletter recaptcha this error was cleared from the console.

0

Issue resolved in 2.3.3 but if you want to fix it in 2.3.2 follow the steps below: create one module with the following structure

enter image description here

1) module.xml

<?xml version="1.0" ?>
<config xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="urn:magento:framework:Module/etc/module.xsd">
    <module name="Levosoft_MSPRecaptchaFixLang" setup_version="1.0.0"/>
</config>

2) requirejs-config.js

var config = {
    map: {
        '*': {
            'MSP_ReCaptcha/js/reCaptcha': "Levosoft_MSPRecaptchaFixLang/js/reCaptcha",
        }
    },
};

3) reCaptcha.js

'use strict';

define(
    [
        'uiComponent',
        'jquery',
        'ko',
        'MSP_ReCaptcha/js/registry'
    ],
    function (Component, $, ko, registry, undefined) {

        return Component.extend({

            defaults: {
                template: 'MSP_ReCaptcha/reCaptcha',
                reCaptchaId: 'msp-recaptcha'
            },
            _isApiRegistered: undefined,

            initialize: function () {
                this._super();
                this._loadApi();
            },

            /**
             * Loads recaptchaapi API and triggers event, when loaded
             * @private
             */
            _loadApi: function () {
                var element, scriptTag;

                if (this._isApiRegistered !== undefined) {
                    if (this._isApiRegistered === true) {
                        $(window).trigger('recaptchaapiready');
                    }

                    return;
                }
                this._isApiRegistered = false;

                // global function
                window.globalOnRecaptchaOnLoadCallback = function () {
                    this._isApiRegistered = true;
                    $(window).trigger('recaptchaapiready');
                }.bind(this);

                element = document.createElement('script');
                scriptTag = document.getElementsByTagName('script')[0];

                element.async = true;
                element.src = 'https://www.google.com/recaptcha/api.js'
                    + '?onload=globalOnRecaptchaOnLoadCallback&render=explicit';
                if (this.settings === undefined || this.settings.lang === null || this.settings.lang === undefined) {
                    element.src = element.src + '&hl=' + window.navigator.language.replace(/-.*/, '');
                } else {
                    element.src = element.src + '&hl=' + this.settings.lang;
                }

                scriptTag.parentNode.insertBefore(element, scriptTag);

            },

            /**
             * Return true if reCaptcha is visible
             * @returns {Boolean}
             */
            getIsVisible: function () {
                return this.settings.enabled[this.zone];
            },

            /**
             * Checking that reCaptcha is invisible type
             * @returns {Boolean}
             */
            getIsInvisibleRecaptcha: function () {
                return this.settings.size !== 'invisible';
            },

            /**
             * Recaptcha callback
             * @param {String} token
             */
            reCaptchaCallback: function (token) {
                if (this.settings.size === 'invisible') {
                    this.tokenField.value = token;
                    this.$parentForm.submit();
                }
            },

            /**
             * Initialize reCaptcha after first rendering
             */
            initCaptcha: function () {
                var me = this,
                    $parentForm,
                    $wrapper,
                    $reCaptcha,
                    widgetId,
                    listeners;

                if (this.captchaInitialized) {
                    return;
                }

                this.captchaInitialized = true;

                /*
                 * Workaround for data-bind issue:
                 * We cannot use data-bind to link a dynamic id to our component
                 * See: https://stackoverflow.com/questions/46657573/recaptcha-the-bind-parameter-must-be-an-element-or-id
                 *
                 * We create a wrapper element with a wrapping id and we inject the real ID with jQuery.
                 * In this way we have no data-bind attribute at all in our reCaptcha div
                 */
                $wrapper = $('#' + this.getReCaptchaId() + '-wrapper');
                $reCaptcha = $wrapper.find('.g-recaptcha');
                $reCaptcha.attr('id', this.getReCaptchaId());

                $parentForm = $wrapper.parents('form');
                me = this;

                // eslint-disable-next-line no-undef
                widgetId = grecaptcha.render(this.getReCaptchaId(), {
                    'sitekey': this.settings.siteKey,
                    'theme': this.settings.theme,
                    'size': this.settings.size,
                    'badge': this.badge ? this.badge : this.settings.badge,
                    'callback': function (token) { // jscs:ignore jsDoc
                        me.reCaptchaCallback(token);
                        me.validateReCaptcha(true);
                    },
                    'expired-callback': function () {
                        me.validateReCaptcha(false);
                    }
                });

                if (this.settings.size === 'invisible') {
                    $parentForm.submit(function (event) {
                        if (!me.tokenField.value) {
                            // eslint-disable-next-line no-undef
                            grecaptcha.execute(widgetId);
                            event.preventDefault(event);
                            event.stopImmediatePropagation();
                        }
                    });

                    // Move our (last) handler topmost. We need this to avoid submit bindings with ko.
                    listeners = $._data($parentForm[0], 'events').submit;
                    listeners.unshift(listeners.pop());

                    // Create a virtual token field
                    this.tokenField = $('<input type="text" name="token" style="display: none" />')[0];
                    this.$parentForm = $parentForm;
                    $parentForm.append(this.tokenField);
                } else {
                    this.tokenField = null;
                }

                registry.ids.push(this.getReCaptchaId());
                registry.captchaList.push(widgetId);
                registry.tokenFields.push(this.tokenField);

            },


            validateReCaptcha: function (state) {
                if (this.settings.size !== 'invisible') {
                    return $(document).find('input[type=checkbox].required-captcha').prop("checked", state);
                }
            },

            /**
             * Render reCaptcha
             */
            renderReCaptcha: function () {
                var me = this;

                if (this.getIsVisible()) {
                    if (window.grecaptcha && window.grecaptcha.render) { // Check if recaptcha is already loaded
                        me.initCaptcha();
                    } else { // Wait for recaptcha to be loaded
                        $(window).on('recaptchaapiready', function () {
                            me.initCaptcha();
                        });
                    }
                }
            },

            /**
             * Get reCaptcha ID
             * @returns {String}
             */
            getReCaptchaId: function () {
                return this.reCaptchaId;
            }
        });
    }
);

4) registration.php

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

That's it run setup upgrade and clear cache.

0

In my case the error was caused by a customization and I took the fix from here: https://github.com/magento/magento2/issues/9635#issuecomment-313758975

In short: delete the following from contact_index_index.xml:

<block class="Magento\Contact\Block\ContactForm" name="contactForm" template="Magento_Contact::form.phtml">
  <container name="form.additional.info" label="Form Additional Info"/>
</block>

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.