Search code examples
angularspartacus-storefrontsap-commerce-cloud

Not Able to Render Image in Spartacus


Product Image is not rendering in the custom Spartacus Component. Below is a code snippet of HTML Code.
I have checked the cx-media which takes the Image container and loads the image. But I was not able to figure out what is missing in my custom Spartacus storefront.

Also no request is triggered from spartacus to get the image. But the same happens on PDP. I am using the OOTB cx-media. Will this not call it internally?

<ng-container *ngIf="model$ | async as model">
<cx-product-list-item
  *ngFor="let product of model?.products"
  [product]="product"
  class="cx-product-search-list"
></cx-product-list-item>
</ng-container>

Response from the Backend

{
   "products" : [ {
      "averageRating" : 4.411764705882353,
      "baseOptions" : [ ],
      "code" : "358639",
      "configurable" : false,
      "images" : [ {
         "altText" : "DSC-N1",
         "format" : "zoom",
         "imageType" : "PRIMARY",
         "url" : "/medias/?context=bWFzdGVyfGltYWdlc3wyNjE4MXxpbWFnZS9qcGVnfGltYWdlcy9oYjYvaDUzLzg3OTcyNjU0NjEyNzguanBnfGI2ZTBiOTI4ZTZlNWEwMWRiYzMwM2YzZTg3ODE5OTQ1ZDdmY2VkZGNiMTBlNjkyZmJmZDExYzIyOTNhZTBhNWM"
      }, {
         "altText" : "DSC-N1",
         "format" : "product",
         "imageType" : "PRIMARY",
         "url" : "/medias/?context=bWFzdGVyfGltYWdlc3wxMjA3OHxpbWFnZS9qcGVnfGltYWdlcy9oODkvaGQxLzg3OTcyOTE3NDEyMTQuanBnfDE2NDc5MDE3MzNiMzIzYmYwOGRkN2YwZjg0MzVhMzRlNTM0ZTIyMWU3N2I4NmM3Mjg0NzUyODUzNTRjODkwZTg"
      }, {
         "altText" : "DSC-N1",
         "format" : "thumbnail",
         "imageType" : "PRIMARY",
         "url" : "/medias/?context=bWFzdGVyfGltYWdlc3wyNDAxfGltYWdlL2pwZWd8aW1hZ2VzL2hlMi9oMzYvODc5NzMxODA4NjY4Ni5qcGd8YTIyNzcxNDBhMWQ3NGU0OWM5NDI0NGE1NGFmNGEzMDk1MjBhNTQ3NGRmMjVmMDBjNjFiN2RmZTY1NDhhMzFkNg"
      }, {
         "altText" : "DSC-N1",
         "format" : "cartIcon",
         "imageType" : "PRIMARY",
         "url" : "/medias/?context=bWFzdGVyfGltYWdlc3wxNDYyfGltYWdlL2pwZWd8aW1hZ2VzL2g0Yi9oMzIvODc5NzM0NDQzMjE1OC5qcGd8YTNkMGQ5MjBjOGQwNDJmNDNjZDE1NmI1ZjRjODYwOWZjNjkzOGZlZTNlODIyNjEzZjlkNmY0YzRhNDI2NjljNQ"
      } ],
      "manufacturer" : "Sony",
      "name" : "DSC-N1",
      "nameHtml" : "DSC-N1",
      "purchasable" : true,
      "summary" : "The Cyber-shot N1 offers 8.1 effective Megapixels with high sensitivity for reduced blur, a massive 3.0\"\" Clear Photo LCD Plus screen with touch-screen operation and a ZEISS 3x Optical Zoom.",
      "url" : "/Open-Catalogue/Cameras/Digital-Cameras/Digital-Compacts/DSC-N1/p/358639"
   }, {
      "averageRating" : 4.6,
      "baseOptions" : [ ],
      "code" : "479956",
      "configurable" : false,
      "images" : [ {
         "altText" : "4GB Memory Stick Pro Duo + adapter",
         "format" : "zoom",
         "imageType" : "PRIMARY",
         "url" : "/medias/?context=bWFzdGVyfGltYWdlc3wyNTQ4M3xpbWFnZS9qcGVnfGltYWdlcy9oYmQvaDY5Lzg3OTcyNjc3NTUwMzguanBnfDVmMmY3ZTI5ZDI5ZDAxNjUxZmQxMjNkYWNhM2MzYjE3MDc3YTJmNmViOTI1M2IwOWQxYWExOTQwODA5NWU2YWQ"
      }, {
         "altText" : "4GB Memory Stick Pro Duo + adapter",
         "format" : "product",
         "imageType" : "PRIMARY",
         "url" : "/medias/?context=bWFzdGVyfGltYWdlc3wxMDkwMHxpbWFnZS9qcGVnfGltYWdlcy9oNjEvaDcwLzg3OTcyOTQwMzQ5NzQuanBnfDk1MTBkMjU5YmRlZjNiNzIzM2IwZGYyZTdiYjZhNDVkOGQzNTdjODk1NDc0NmIxZDI4OWIwZTlhMDExMDUwYjQ"
      }, {
         "altText" : "4GB Memory Stick Pro Duo + adapter",
         "format" : "thumbnail",
         "imageType" : "PRIMARY",
         "url" : "/medias/?context=bWFzdGVyfGltYWdlc3wyMDQwfGltYWdlL2pwZWd8aW1hZ2VzL2gyMC9oODQvODc5NzMyMDM4MDQ0Ni5qcGd8OWRiOTk2YzY5MmUyOWNhNGIwM2ViNTI0YjBkMzBhMzllNDFkOWI0MWNiZmY3MDE1M2E3YjZkM2MzZmU2MzdjMA"
      }, {
         "altText" : "4GB Memory Stick Pro Duo + adapter",
         "format" : "cartIcon",
         "imageType" : "PRIMARY",
         "url" : "/medias/?context=bWFzdGVyfGltYWdlc3wxMzQ3fGltYWdlL2pwZWd8aW1hZ2VzL2g3YS9oNjIvODc5NzM0NjcyNTkxOC5qcGd8YjczMDkxYzM0ZmY1NTc4MjEzOWU4Yzk3NGVlOWI5MjAxMTE4NTY1ZTBlNGIwY2UyNjRkZDhiNGE3ZmZkMWM0OA"
      } ],
      "manufacturer" : "Sony",
      "name" : "4GB Memory Stick Pro Duo + adapter",
      "nameHtml" : "4GB Memory Stick Pro Duo + adapter",
      "purchasable" : true,
      "summary" : "MSX-M4GSX - 4GB Memory Stick Pro Duo + adapter",
      "url" : "/Open-Catalogue/Data-storage/Flash-Memory/4GB-Memory-Stick-Pro-Duo-%2B-adapter/p/479956"
   }, {
      "averageRating" : 5.0,
      "baseOptions" : [ ],
      "code" : "1377492",
      "configurable" : false,
      "images" : [ {
         "altText" : "Micro Webcam",
         "format" : "zoom",
         "imageType" : "PRIMARY",
         "url" : "/medias/?context=bWFzdGVyfGltYWdlc3wxMzI2N3xpbWFnZS9qcGVnfGltYWdlcy9oMDQvaGEzLzg3OTcyNTAxOTEzOTAuanBnfDFhNTIzZWY5M2E3NjMzZWQ5NGM4OGRlMDM0OGFjOGRmNDJiODVjMmJkM2YxMjZhZWI0NDkyMWFiZDMxOGJmOTA"
      }, {
         "altText" : "Micro Webcam",
         "format" : "product",
         "imageType" : "PRIMARY",
         "url" : "/medias/?context=bWFzdGVyfGltYWdlc3wzMDk0NXxpbWFnZS9qcGVnfGltYWdlcy9oNWUvaDgxLzg3OTcyNzY1MzY4NjIuanBnfGM5M2ViZmQ2MmE4NjYwY2NlY2VjYzNhYmE1OGFhY2QxNThmMjE4YmMxYWRiMmU4ZDBhNzk2MjlmZDYyMzBiOGE"
      }, {
         "altText" : "Micro Webcam",
         "format" : "thumbnail",
         "imageType" : "PRIMARY",
         "url" : "/medias/?context=bWFzdGVyfGltYWdlc3wxNzgzfGltYWdlL2pwZWd8aW1hZ2VzL2g0OS9oNTUvODc5NzMwMjgxNjc5OC5qcGd8NjQ2MmM2MDgxZmUyNzU0YjJkMTY3NDM3MDJkNmFiYzQ4MzljMWFhN2QwMTVhYjliZjU0ZGMxNWZjNWViYjgzNg"
      }, {
         "altText" : "Micro Webcam",
         "format" : "cartIcon",
         "imageType" : "PRIMARY",
         "url" : "/medias/?context=bWFzdGVyfGltYWdlc3wxMjMyfGltYWdlL2pwZWd8aW1hZ2VzL2g4My9oNTAvODc5NzMyOTE2MjI3MC5qcGd8MWMyZGY2Mzk4NGQ2ZjA5NGM3NWQ1ZDcwNjczNjRmMDYzZDY1YWUxZTY4ZTY3YTZjMDU3ZGIyNzMzMGFkM2RiNQ"
      } ],
      "manufacturer" : "Targus",
      "name" : "Micro Webcam",
      "nameHtml" : "Micro Webcam",
      "purchasable" : true,
      "url" : "/Open-Catalogue/Cameras/Webcams/Micro-Webcam/p/1377492"
   }, {
      "averageRating" : 2.607142857142857,
      "baseOptions" : [ ],
      "code" : "1986316",
      "configurable" : false,
      "images" : [ {
         "altText" : "LEGRIA HF S100",
         "format" : "zoom",
         "imageType" : "PRIMARY",
         "url" : "/medias/?context=bWFzdGVyfGltYWdlc3wyNjU1MnxpbWFnZS9qcGVnfGltYWdlcy9oZDMvaGY5Lzg3OTcyNTU4Mjc0ODYuanBnfDZjMzRhZjBlN2JlMWZlM2UyZDJiNmM4OTRkODc0NTI3Y2QyNWZiOTgxZjFkMTkwMDc3YmJhNTQ4MDliM2M2NmU"
      }, {
         "altText" : "LEGRIA HF S100",
         "format" : "product",
         "imageType" : "PRIMARY",
         "url" : "/medias/?context=bWFzdGVyfGltYWdlc3w1OTg4NHxpbWFnZS9qcGVnfGltYWdlcy9oNzcvaDExLzg3OTcyODIxNzI5NTguanBnfDc0YmI4N2I2ZGRmMDYxMzYyZWU0MjJjM2UzYmU0ZTZkZmM3MDU0YjZlNTYxYmNkYjk5OGNjYzljNDY3MTcyMGE"
      }, {
         "altText" : "LEGRIA HF S100",
         "format" : "thumbnail",
         "imageType" : "PRIMARY",
         "url" : "/medias/?context=bWFzdGVyfGltYWdlc3wyMjMxfGltYWdlL2pwZWd8aW1hZ2VzL2hkNC9oODUvODc5NzMwODQ1Mjg5NC5qcGd8OWQyY2U0MTI5ODBhMzU4MmM4ZDE0NWQ2OGVhMzMwY2IzZDZlYjY5Mjc5NDM1YjVlY2FlOWIzNTQ4NDIzNjVmOQ"
      }, {
         "altText" : "LEGRIA HF S100",
         "format" : "cartIcon",
         "imageType" : "PRIMARY",
         "url" : "/medias/?context=bWFzdGVyfGltYWdlc3wxNDE2fGltYWdlL2pwZWd8aW1hZ2VzL2g5Ny9oMjAvODc5NzMzNDc5ODM2Ni5qcGd8OGI5YzQ0MzIzMDA1MGI4YzlmYTgwMzZkMmJlMGQ5M2M0YWExOTQ5OTViOGM1ZTVmNWIzZTFkMmFiNDdkNTFmZA"
      } ],
      "manufacturer" : "Canon",
      "name" : "LEGRIA HF S100",
      "nameHtml" : "LEGRIA HF S100",
      "purchasable" : true,
      "summary" : "LEGRIA HF S100 - SD/SDHC, 1/2.6\"\" CMOS, 8.59 megapixel, 6.4 - 64mm, 10x Optical, DIGIC DV III, 2.7\"\" LCD, 0.3 lux, 1/6 - 1/2000th sec., USB/HDMI",
      "url" : "/Open-Catalogue/Cameras/Hand-held-Camcorders/LEGRIA-HF-S100/p/1986316"
   } ]
}

Below is the Module

   import { ModuleWithProviders, NgModule } from '@angular/core';
import { CommonModule } from '@angular/common';
import { BuyAgainComponent } from './buyAgain.component';
import { CmsConfig, provideDefaultConfig } from '@spartacus/core';
import { MediaModule, ProductListModule } from '@spartacus/storefront';

@NgModule({
  imports: [CommonModule,
    ProductListModule,
  MediaModule],
  providers: [
    provideDefaultConfig(<CmsConfig>{
      cmsComponents: {
        BuyAgainComponent: {
          component: BuyAgainComponent,
        },
      },
    }),
  ],
  declarations: [BuyAgainComponent],
  exports: [BuyAgainComponent],
})
export class BuyAgainModule {}

Below is the Configuration Module

@NgModule({
  declarations: [],
  imports: [
    LayoutConfigurationModule,
    ExtendServices,
    BuyAgainModule,
    HttpClientModule,
    BaseOccModule
  ],
  providers: [provideConfig(mediaConfig), ...defaultCmsContentProviders, provideConfig(<OccConfig>{
    backend: {
      occ: {
        baseUrl: 'https://localhost:9002/',
      }
    },

Here is the Inspect Element tool screenshot

Element tool screenshot

Result:

Product Image Not rendering


Solution

  • I think the response is simple 😁

    TL;DR : Apply normalizer pipe as soon as you get the data:

    constructor(private converterService: ConverterService) // inject the service
    ...
    
    .pipe(this.converterService.pipeable(PRODUCT_NORMALIZER)) // pipe the received products
    

    Explanation: Spartacus usually needs to apply a normalize process over the data that comes from BE; in particular, for products, it normalizes the product data and the images; Inside product-image-normalizer.ts, it can be seen how it groups the images by imageType and format. The ProductListItemComponent component that you are using (cx-product-list-item) is implemented like this:

      <cx-media
        class="cx-product-image"
        [container]="product.images?.PRIMARY"
        format="product"
        [alt]="product.summary"
      ></cx-media>
    

    And you may notice that for data that hasn't been normalized, product.images?.PRIMARY will be providing a null value for container input parameter, which prevents the image from being shown:

      protected create(): void {
        this.media = this.mediaService.getMedia(
          this.container,
          this.format,
          this.alt,
          this.role
        );
        if (!this.media?.src) {
          this.handleMissing();
        }
      }
    

    So, once the code for normalize the products is added, I'm pretty sure it will work. Please let me know how it was 🙂 Cheers!