Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

MAGE-6 Fix: recommend.js get null from script when script loading bef… #1571

Open
wants to merge 1 commit into
base: release/3.14.0-beta
Choose a base branch
from
Open
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
159 changes: 84 additions & 75 deletions view/frontend/web/recommend.js
Original file line number Diff line number Diff line change
Expand Up @@ -8,107 +8,116 @@ define([
],function ($, algoliaBundle, recommend, recommendJs, recommendProductsHtml) {
'use strict';

if (typeof algoliaConfig === 'undefined') {
return;
}

return function (config, element) {
$(function ($) {
this.defaultIndexName = algoliaConfig.indexName + '_products';
const appId = algoliaConfig.applicationId;
const apiKey = algoliaConfig.apiKey;
const recommendClient = recommend(appId, apiKey);
const indexName = this.defaultIndexName;
if ($('body').hasClass('catalog-product-view') || $('body').hasClass('checkout-cart-index')) {
// --- Add the current product objectID here ---
if ((algoliaConfig.recommend.enabledFBT && $('body').hasClass('catalog-product-view')) || (algoliaConfig.recommend.enabledFBTInCart && $('body').hasClass('checkout-cart-index'))) {
recommendJs.frequentlyBoughtTogether({
container: '#frequentlyBoughtTogether',

function checkerConfigLoading() {
if (typeof algoliaConfig === 'undefined')
setTimeout(checkerConfigLoading, '500')
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@sgeleon This seems like potential for an endless loop. I'd be more interested in why algoliaConfig object doesn't load when expected so we can be sure to properly load the dependency. Can you please provide the steps to recreate this scenario?

FWIW the underlying code is a bit old. The legacy use of the global window object for dependencies that we are trying to ensure load through RequireJS creates some challenges for us. It is not ideal and may be refactored in the future but we want to do it right. The more input you guys give us, the more it helps us to nail this stuff down! Feedback is welcome. 🙂

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hello @cammonro.

This seems like potential for an endless loop.

No, because RequireJS executes this script only once when loading require.js. The loop stops when the value is defined.

I'd be more interested in why algoliaConfig object doesn't load when expected so we can be sure to properly load the dependency. Can you please provide the steps to recreate this scenario?

In your setup, we don't see algoliaConfig. This value is not managed by RequireJS.

define([
    'jquery',
    'algoliaBundle',
    'recommend',
    'recommendJs',
    'recommendProductsHtml',
    'domReady!'
],function ($, algoliaBundle, recommend, recommendJs, recommendProductsHtml) {

In this case, we check the value of algoliaConfig, which is not controlled by RequireJS. This value might not be defined during script execution.

    if (typeof algoliaConfig === 'undefined') {
        return;
    }

else
exec()
}

function exec() {

$(function ($) {
this.defaultIndexName = algoliaConfig.indexName + '_products';
const appId = algoliaConfig.applicationId;
const apiKey = algoliaConfig.apiKey;
const recommendClient = recommend(appId, apiKey);
const indexName = this.defaultIndexName;
if ($('body').hasClass('catalog-product-view') || $('body').hasClass('checkout-cart-index')) {
// --- Add the current product objectID here ---
if ((algoliaConfig.recommend.enabledFBT && $('body').hasClass('catalog-product-view')) || (algoliaConfig.recommend.enabledFBTInCart && $('body').hasClass('checkout-cart-index'))) {
recommendJs.frequentlyBoughtTogether({
container: '#frequentlyBoughtTogether',
recommendClient,
indexName,
objectIDs: config.algoliObjectId,
maxRecommendations: algoliaConfig.recommend.limitFBTProducts,
transformItems: function (items) {
return items.map((item, index) => ({
...item,
position: index + 1,
}));
},
headerComponent({html}) {
return recommendProductsHtml.getHeaderHtml(html, algoliaConfig.recommend.FBTTitle);
},
itemComponent({item, html}) {
return recommendProductsHtml.getItemHtml(item, html, algoliaConfig.recommend.isAddToCartEnabledInFBT);
},
});
}
if ((algoliaConfig.recommend.enabledRelated && $('body').hasClass('catalog-product-view')) || (algoliaConfig.recommend.enabledRelatedInCart && $('body').hasClass('checkout-cart-index'))) {
recommendJs.relatedProducts({
container: '#relatedProducts',
recommendClient,
indexName,
objectIDs: config.algoliObjectId,
maxRecommendations: algoliaConfig.recommend.limitRelatedProducts,
transformItems: function (items) {
return items.map((item, index) => ({
...item,
position: index + 1,
}));
},
headerComponent({html}) {
return recommendProductsHtml.getHeaderHtml(html, algoliaConfig.recommend.relatedProductsTitle);
},
itemComponent({item, html}) {
return recommendProductsHtml.getItemHtml(item, html, algoliaConfig.recommend.isAddToCartEnabledInRelatedProduct);
},
});
}
}

if ((algoliaConfig.recommend.isTrendItemsEnabledInPDP && $('body').hasClass('catalog-product-view')) || (algoliaConfig.recommend.isTrendItemsEnabledInCartPage && $('body').hasClass('checkout-cart-index'))) {
recommendJs.trendingItems({
container: '#trendItems',
facetName: algoliaConfig.recommend.trendItemFacetName ? algoliaConfig.recommend.trendItemFacetName : '',
facetValue: algoliaConfig.recommend.trendItemFacetValue ? algoliaConfig.recommend.trendItemFacetValue : '',
recommendClient,
indexName,
objectIDs: config.algoliObjectId,
maxRecommendations: algoliaConfig.recommend.limitFBTProducts,
transformItems:function (items) {
maxRecommendations: algoliaConfig.recommend.limitTrendingItems,
transformItems: function (items) {
return items.map((item, index) => ({
...item,
position: index + 1,
}));
},
headerComponent({html}) {
return recommendProductsHtml.getHeaderHtml(html,algoliaConfig.recommend.FBTTitle);
return recommendProductsHtml.getHeaderHtml(html, algoliaConfig.recommend.trendingItemsTitle);
},
itemComponent({item, html}) {
return recommendProductsHtml.getItemHtml(item, html, algoliaConfig.recommend.isAddToCartEnabledInFBT);
return recommendProductsHtml.getItemHtml(item, html, algoliaConfig.recommend.isAddToCartEnabledInTrendsItem);
},
});
}
if ((algoliaConfig.recommend.enabledRelated && $('body').hasClass('catalog-product-view')) || (algoliaConfig.recommend.enabledRelatedInCart && $('body').hasClass('checkout-cart-index'))) {
recommendJs.relatedProducts({
container: '#relatedProducts',
} else if (algoliaConfig.recommend.enabledTrendItems && typeof config.recommendTrendContainer !== "undefined") {
let containerValue = "#" + config.recommendTrendContainer;
recommendJs.trendingItems({
container: containerValue,
facetName: config.facetName ? config.facetName : '',
facetValue: config.facetValue ? config.facetValue : '',
recommendClient,
indexName,
objectIDs: config.algoliObjectId,
maxRecommendations: algoliaConfig.recommend.limitRelatedProducts,
transformItems:function (items) {
maxRecommendations: config.numOfTrendsItem ? parseInt(config.numOfTrendsItem) : algoliaConfig.recommend.limitTrendingItems,
transformItems: function (items) {
return items.map((item, index) => ({
...item,
position: index + 1,
}));
},
headerComponent({html}) {
return recommendProductsHtml.getHeaderHtml(html,algoliaConfig.recommend.relatedProductsTitle);
return recommendProductsHtml.getHeaderHtml(html, algoliaConfig.recommend.trendingItemsTitle);
},
itemComponent({item, html}) {
return recommendProductsHtml.getItemHtml(item, html, algoliaConfig.recommend.isAddToCartEnabledInRelatedProduct);
return recommendProductsHtml.getItemHtml(item, html, algoliaConfig.recommend.isAddToCartEnabledInTrendsItem);
},
});
}
}
});
}

if ((algoliaConfig.recommend.isTrendItemsEnabledInPDP && $('body').hasClass('catalog-product-view')) || (algoliaConfig.recommend.isTrendItemsEnabledInCartPage && $('body').hasClass('checkout-cart-index'))) {
recommendJs.trendingItems({
container: '#trendItems',
facetName: algoliaConfig.recommend.trendItemFacetName ? algoliaConfig.recommend.trendItemFacetName : '',
facetValue: algoliaConfig.recommend.trendItemFacetValue ? algoliaConfig.recommend.trendItemFacetValue : '',
recommendClient,
indexName,
maxRecommendations: algoliaConfig.recommend.limitTrendingItems,
transformItems:function (items) {
return items.map((item, index) => ({
...item,
position: index + 1,
}));
},
headerComponent({html}) {
return recommendProductsHtml.getHeaderHtml(html,algoliaConfig.recommend.trendingItemsTitle);
},
itemComponent({item, html}) {
return recommendProductsHtml.getItemHtml(item, html, algoliaConfig.recommend.isAddToCartEnabledInTrendsItem);
},
});
} else if (algoliaConfig.recommend.enabledTrendItems && typeof config.recommendTrendContainer !== "undefined") {
let containerValue = "#" + config.recommendTrendContainer;
recommendJs.trendingItems({
container: containerValue,
facetName: config.facetName ? config.facetName : '',
facetValue: config.facetValue ? config.facetValue : '',
recommendClient,
indexName,
maxRecommendations: config.numOfTrendsItem ? parseInt(config.numOfTrendsItem) : algoliaConfig.recommend.limitTrendingItems,
transformItems:function (items) {
return items.map((item, index) => ({
...item,
position: index + 1,
}));
},
headerComponent({html}) {
return recommendProductsHtml.getHeaderHtml(html,algoliaConfig.recommend.trendingItemsTitle);
},
itemComponent({item, html}) {
return recommendProductsHtml.getItemHtml(item, html, algoliaConfig.recommend.isAddToCartEnabledInTrendsItem);
},
});
}
});
checkerConfigLoading()
}
});