0

My problem: I have a observableArray packageItems linked to my template which works fine on the initial load, but after trying to alter it by a function called from another component, the array changes, but the template doesn't update anymore.

Quick overview: I have two components PackagePopup -> responsible for loading and displaying items in my popup PackageFilter -> responsible for rendering of filters for the items.

Defined in x-magento-init as follows:

    <script type="text/x-magento-init">
    {
        "#product-package-modal-<?=$productPackage->getId();?>":{
            "Magento_Ui/js/core/app":{
                "components":{
                    "package-popup-<?=$productPackage->getId();?>":{
                        "component": "Namespace_ProductPackage/js/packagepopup",
                        "template" : "Namespace_ProductPackage/packagepopup",
                        "productPackage" :  <?= /* @escapeNotVerified */ $block->getProductPackageJson($productPackage); ?>,
                        "store_id" : <?=$block->getCurrentStoreId();?>,
                        "mainproduct_id" : <?=$block->getCurrentProductId();?>,
                        "children": {
                            "package-filters-<?=$productPackage->getId();?>":{
                                "component": "Namespace_ProductPackage/js/packagefilter",
                                "template" : "Namespace_ProductPackage/packagefilter",
                                "productpackage_id" :  <?= /* @escapeNotVerified */ $productPackage->getId() ?>,
                                "store_id" : <?= $block->getCurrentStoreId();?>,
                                "mainproduct_id" : <?= $block->getCurrentProductId();?>,
                                "config": {
                                    "provider": "package-popup-<?=$productPackage->getId();?>"
                                }
                            }
                        }
                    }
                }
            }
        }
    }
</script>

My packagepopup is as follows:

define(['uiComponent', 'ko', 'jquery', 'mage/url','uiRegistry'], function (Component, ko, $,url, uiRegistry) {
"use strict";

return Component.extend({
    store_id:0,
    productpackage_id: 0,
    mainproduct_id:0,
    template_identifier:'pp-filters-',

    initialize: function (config) {
        this._super();
        this.store_id = config.store_id;
        this.mainproduct_id = config.mainproduct_id;
        this.productpackage_id = config.productpackage_id;
        this.observe('filterData');
        this.getFilterData();
    },
    parentComponent: function()
    {
      return  uiRegistry.get(this.parentName);
    },
    getHtmlId: function(){
        return this.template_identifier + this.getId();
    },
    getId: function () {
        return this.productpackage_id;
    },
    /**
     * Asynchrounously loads the filters that apply to this productpackage
     */
    getFilterData: function () {
        var self = this;
        let requestUrl = url.build('productpackage/index/filters/') + 'productpackage_id/' + self.getId();
        jQuery.getJSON(requestUrl, function (data) {
            self.filterData(data);
        }).fail(function () {
            console.log('Failed loading filterdata');
        });
    },
    /**
     * Dynamically assigngs the template file for the filter based on type
     */
    getFilterTemplateName: function(filterData)
    {
        let frontend_input = (filterData.frontend_input == 'select') ? 'multiselect' :  filterData.frontend_input;
        return 'Namespace_ProductPackage/filters/'+frontend_input;
    },
    /**
     * Loops trough the filters in dom and collects their current values
     */
    getFilterValues: function()
    {
        var values = new Array();
        var attribute_code;
        // for each attribute filter for this view
        $('#' + this.getHtmlId() + ' div.pp-filter-attribute').each(function(e){
            attribute_code = $(this).attr('attribute_code');
            if(!values[attribute_code]){
                values[attribute_code] = new Array();
            }
            // for each checked value under this attribute
            $(this).find(".pp-filter-content ol>li input:checked").each(function(){
               values[attribute_code].push($(this).attr('value_id'));
            });
        return values;

    },
    /**
     * When a certain filter is changed send this change to the package.
     */
    filterChange: function()
    {
        let filters = this.getFilterValues();
        this.parentComponent().setFilters(filters);
    }
});

});

The function FilterChange is called by one of the filters:

As you can see, the FilterChange calls the parentComponent's setFilters function. This function sets this.activeFilters and then triggers applyFiltersOnPackageItems which loops trough the packageitems and applies the filters by setting the packageItem.is_visible.

define(['Namespace_ProductPackage/js/baseproductpackage', 'Magento_Ui/js/modal/modal', 'jquery', 'ko', 'mage/url'], function (BasePackageComponent, modal, $, ko, url) {
return BasePackageComponent.extend({
        packageitemPagePosition:1,

    initialize: function (config) {
        this._super(config);
        this.activeFilters = new Array;
        this.packageItems = ko.observableArray();
        this.getPackageItems(1,30);
        this.initModal();
    },
    /**
     * Initialize the Modal window with the magento modal component
     */
    initModal: function () {
        var modalWindow = $("#product-package-modal-" + this.getId()),
            modalOptions = {
                title: this.title,
                'type': 'popup',
                'modalClass': "product-package-modal-" + this.getId() + " productpackage-modal",
                'responsive': true,
                'innerScroll': true,
                'trigger': '.show-product-package-modal-' + this.getId(),
                'buttons': []
            };
        modal(modalOptions, modalWindow);
    },

       ...  some functions here ....
     /**
     * Take the current package items and apply each filter in
     * this.activeFilters to it.
     */
    applyFiltersOnPackageItems: function()
    {
        let currentPackageItems = this.packageItems();
        this.packageItems().forEach((packageItem, index) => {

            let packageCopy = JSON.parse(JSON.stringify(packageItem));

            packageItem = this.applyFilters(packageItem);

            this.packageItems.replace(packageCopy,packageItem);
            console.log(index+ ' NEW ' +packageItem.is_visible + ' -> '+ packageItem.product.name )

        });
        console.log(this.packageItems());
        this.packageItems.valueHasMutated();

                    //for testing purposes
        this.packageItems()[4].is_visible = false;

        this.packageItems(currentPackageItems);
        console.log(this.packageItems());*/
    },
    /**
     * Called by the filters Component, sets the activeFilters
     * @param filters
     */
    setFilters: function(filters)
    {
        this.activeFilters = filters;
        this.applyFiltersOnPackageItems();
    }
});

});

In my template, i can see the is_visible works in my template since altering it, changes it. Also, the callback from the filters Component changes my observableArray which i can see by printing it. However, the changes taking place in applyFiltersOnPackageItems do not affect my template, the is_visible of the packageitems in the template linked to the observableArray don't change.

Console.log(this.packageItems()) at end of applyFiltersOnPackageItems shows the following:

enter image description here

However, the template still shows is_visible=true for element with index 1.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Browse other questions tagged or ask your own question.