Magento Knockout динамически индексирует массив данных продукта с вычисляемой функцией

поэтому я пытаюсь создать особый тип блока «карточка продукта» на главной странице M2. Идея состоит в том, что блок с информацией о продукте для выбранного в данный момент продукта в раскрывающемся списке layout

Я реализовал следующие файлы, чтобы попытаться достичь этой цели:

приложение/код/поставщик/модуль/представление/интерфейс/веб/js/представление/подписки-group.js

/**
 * @category Vendor
 * @package Vendor\Module
 * @copyright Copyright (c) 2021 Vendor Media Limited (http://www.Vendor.co.uk/)
 * @license http://opensource.org/licenses/afl-3.0.php Academic Free License (AFL 3.0)
 */

define([
    'uiElement',
    'underscore',
    'jquery',
    'ko',
    'mage/translate',
    'Magento_Ui/js/model/messageList'
], function (Element, _, $, ko, $t, messageList) {
    'use strict';

    return Element.extend({
        defaults: {
            template: 'Vendor_Module/products-group',
            productGroup: null,
            ajaxHttpMethod: 'POST',
            productsRendered: 0,
            productData: ko.observableArray([]),
            currentId: ko.observable(0),
            currentProduct: ko.pureComputed(function () { return {};}).bind(this),
            imports: {
                ajaxUrl: '${ $.provider }:ajaxUrl',
                showDescription: '${ $.provider }:showDescription'
            }
        },
        loadingInProgress: ko.observable(false),
        errorMessage: ko.observable(null),
        warningMessage: ko.observable(null),

        initialize: function () {
            this._super();
            ko.options.deferUpdates = true;
            let self = this;

            this.currentProduct = ko.pureComputed(function (){
                return self.productData[self.currentId()] || {};
            }, self).bind(this);

            this.getProductData()
                .done(function(response) {
                    Object.values(JSON.parse(response)).forEach(function(product) {
                        self.productData.push(product);
                    });
                    self.currentId.valueHasMutated();
                    console.log(self.currentProduct());
                }, self)
                .fail(function(err) {
                    console.error(`Failed to get product data for group ${ self.productGroup }`);
                    console.error(err.message);
                }, self);

            return this;
        },

        getProductData: function() {
            return $.ajax({
                accepts: {
                    text: "application/json"
                },
                url: this.ajaxUrl,
                type: this.ajaxHttpMethod,
                dataType: 'json',
                data: {
                    group: this.productGroup
                }
            })
        }
    });
});

app/code/Vendor/Module/view/frontend/templates/subscription-list.phtml

/** @var Subscriptions $block */
$_productCollection = $block->getProducts();
/** @var Vendor\Module\Helper\Config $_configHelper */
$_configHelper = $this->helper(ConfigHelper::class);

// Display definitions
$viewMode = 'list';
$image = 'category_page_list_image';
$showDescription = true;
$i = 0;
?>
<?php if (!$_productCollection || !count($_productCollection)): ?>
    <div class="message info empty">
        <div><?php
            echo __('You do not have any subscriptions.') ?></div>
    </div>
<?php else: ?>
    <div class="products wrapper <?= $viewMode ?> products-<?= $viewMode ?>" data-bind="scope: 'subscriptionsList'">
        <ol class="products list items product-items">
            <!-- ko foreach: elems() -->
                <li class="item product product-item product-item-info" data-container="product-grid" data-bind="template: { name: getTemplate(), data: currentProduct}">
                </li>
            <!-- /ko -->
        </ol>
    </div>
<?php endif; ?>
<script>
    window.subscriptionConfig = <?= Zend_Json::encode($block->getSubscriptionConfig()) ?>;
</script>
<script type="text/x-magento-init">
{
    "*": {
        "Magento_Ui/js/core/app": {
            "components": {
                "subscriptionsList": {
                    "component": "Vendor_Module/js/view/subscriptions-list",
                    "config": {
                        "ajaxUrl": "<?= $block->getUrl($_configHelper::PRODUCT_DATA_AJAX_URL) ?>",
                        "showDescription": "<?= json_encode($block->showDescription()) ?>",
                        "viewMode": "<?= $viewMode ?>",
                        "image": "<?= $image ?>"
                    },
                    "children": {
                        "groupListIncontrol": {
                            "component": "Vendor_Module/js/view/subscriptions-group",
                            "config": {
                                "provider": "subscriptionsList",
                                "productGroup": "<?= $_configHelper::PRODUCT_GROUP_INCONTROL ?>"
                            }
                        },
                        "groupListOnlinePack": {
                            "component": "Vendor_Module/js/view/subscriptions-group",
                            "config": {
                                "provider": "subscriptionsList",
                                "productGroup": "<?= $_configHelper::PRODUCT_GROUP_ONLINE_PACK ?>"
                            }
                        }
                    }
                }
            }
        }
    }
}
</script>

app/code/Vendor/Module/view/frontend/web/template/products-group.html (это находится в процессе преобразования чистого php в ko, так что выглядит беспорядок, приносим извинения)

<!--
 @category Vendor
 @package Vendor\Module
 @copyright Copyright (c) 2021 Vendor Media Limited (http://www.Vendor.co.uk/)
 @license http://opensource.org/licenses/afl-3.0.php Academic Free License (AFL 3.0)
 -->
<!--Fix product group to be dynamic-->
<!--<ol class="products list items product-items" data-bind="class: productGroup">-->
<!--    <div class="top-product-container">-->
<!--        <span class="name-wrapper" data-bind="accessObj: {  obj: currentProduct, key: 'name' } "></span>-->
<!--&lt;!&ndash;        <?php  echo $block->getProductPrice($_product) ?>&ndash;&gt;-->
<!--        <div class="price-box price-final_price" data-role="priceBox" data-product-id="5406" data-price-box="product-id-5406">-->
<!--            <span class="price-container price-final_price tax weee">-->
<!--                <span id="product-price-5406" data-price-amount="99" data-price-type="finalPrice" class="price-wrapper "><span class="price" data-bind="accessObj: {  obj: currentProduct, key: 'price' }"></span></span>-->
<!--            </span>-->
<!--        </div>-->
<!--    </div>-->
<!--</ol>-->

<span class="stripped-name" data-bind="text: nameStripped" style="display: none;"></span>
<div class="top-product-container">
<!--        <?php  echo $block->getProductPrice($_product) ?>-->
    <label for="select_subscription_<?php echo $i ?>" class="product name product-item-name">
        <span class="name-wrapper" data-bind="text: name"></span>
    </label>
    <div class="price-box price-final_price" data-role="priceBox" data-product-id="5406" data-price-box="product-id-5406">
        <span class="price-container price-final_price tax weee">
            <span id="product-price-5406" data-price-amount="99" data-price-type="finalPrice" class="price-wrapper "><span class="price" data-bind="text: getCurrentAttribute('price')"></span></span>
        </span>
    </div>
</div>
<div class="info-container">
    <div class="product-image" data-bind="text: getCurrentAttribute('imageHtml')">
    </div>
    <div class="info-block">
        <?php if ($showDescription):?>
        <div class="product description product-item-description">
            <?php echo $_helper->productAttribute($_product, $_product->getShortDescription(), 'short_description'); ?>
            <?php $longDesc = $_helper->productAttribute($_product, $_product->getDescription(), 'description'); ?>
            <?php if ($longDesc): ?>
            <?php if (!$block->showDescription()): ?>
            <a onclick="jQuery(this).next().toggle(); jQuery(this).hide();" title="<?php  echo $_productNameStripped ?>" class="action more">
                <?php echo __('Read More...'); ?>
            </a>
            <?php endif; ?>
            <div class="long-desc" <?php if ($block->showDescription()): ?>style="display: block;"<?php endif; ?>>
            <?php echo $longDesc; ?>
        </div>
        <?php endif; ?>
    </div>
    <?php endif; ?>
    <?php if ($note = $_helper->productAttribute($_product, $_product->getProductNote(), 'product_note')): ?>
    <div class="note">
        <?php echo $note ?>
    </div>
    <?php endif; ?>
</div>
</div>

В UiComponent я вызываю контроллер M2 JSON, который возвращает список объектов JSON, каждый из которых представляет собой все соответствующие данные о продукте для отображения для product_id. Я проверил с помощью отладчика, что эти данные поступают

Итак, есть 2 проблемы с ним:

  1. subscriptions-list.phtml не нравится data-bind="template: { name: getTemplate(), data: currentProduct}", он говорит: «невозможно прочитать имя свойства» неопределенного. Я попытался создать эту привязку шаблона по совету этот ответ
  2. Когда страница загружается, оба this.productData наблюдаемых массива показывают точно одни и те же данные, хотя я собственными глазами убедился, что они получают разные ответы данных (отладчик). Мне кажется, что это свойство каким-то образом распределяется между дочерними элементами, потому что оно заканчивается конкатенацией обоих массивов, возвращаемых из контроллера

person Scott Anderson    schedule 31.05.2021    source источник