Related Github Documents
Document Properties
Kbid
298A19
Last Modified
26-Mar-2021
Added to KB
09-Mar-2021
Public Access
Everyone
Status
Online
Doc Type
Guidelines, Concepts & Cookbooks
Product
Intershop Progressive Web App

Guide - Intershop Progressive Web App - Product Context

Product Context

Product Contexts were introduced in PWA version 0.27.

What is a Product Context?

Product contexts provide easy access to all data related to a single product.
The context itself stores the sku and (optional) the quantity of the product and delegates all other information from the State Management in a simplified fashion.

The following screenshots provide examples where product contexts are used on some pages:

Product contexts used for recommendations Product contexts used for product listings Product contexts used for product bundles Product contexts used for wish lists

For product pages, there is always one context that spans the entire content of the product page.
However, additional contexts for recommended products or bundled products may exist on the page.
For listings of any kind, individual contexts exist on the page for each product.
Product Contexts can also be linked to their parent contexts.

How to Introduce Product Context?

Unlike regular facades, which are available globally and have only one instance available at runtime, context facades are provided using ElementInjector and are therefore only available for elements enclosed in the document subtree for which the element introduced the context.

By Using ProductContextDirective

The easiest way to start a product context is by using the ProductContextDirective on templates:

<ng-container *ngFor="let item of lineItems$ | async">
  <div class="..." ishProductContext [sku]="item.sku">
    <ish-product-name></ish-product-name>
  </div>
</ng-container>

What happens here?

  • For each individual item from lineItems$, a product context for embedded elements is provided.
  • Each individual context is associated with item.sku which also triggers fetching the product if it is not already available in the store.
  • The ish-product-name component will render the product name.

This also portrays one of the main advantages of using this concept: No bubbling of product related data is necessary anymore.
The ish-product-name component injects the provided context and decides which data is used for rendering.

Note: ProductDetailComponent is only used for layout and styling, whereas the context is provided by the outer ProductPageComponent.

By Providing ProductContextFacade

There are cases for which it is not possible to use the directive: For example, when the parent component does not have access to all required information or when the component has to introduce another context by itself.
In this case the ProductContextFacade has to be added to the providers array of the @Component decorator.
Afterwards, the SKU for the context has to be initialized:

@Component({
  ...
  providers: [ProductContextFacade],
})
export class MyComponent implements OnInit {
  constructor(private context: ProductContextFacade) {}

  ngOnInit() {
    this.context.set('sku', () => this.staticValue);
    // or
    this.context.connect('sku', this.streamValue$);
  }
}

By Providing SelectedProductContextFacade

For pages that use the :sku route parameter, the product context can be introduced on page level by using SelectedProductContextFacade.

Have a look at ProductPageComponent for an example.

Retrieving Data from the Product Context

Inject ProductContextFacade

The easiest way to interact with the context is to do the same as you would do with facades.
Inject the ProductContextFacade into your components and relay data for the template into observables and use the async pipe there:

@Component({ ... })
export class MyComponent implements OnInit {
  available$: Observable<boolean>;

  constructor(private context: ProductContextFacade) {}

  ngOnInit() {
    this.available$ = this.context.select('product', 'available');
  }

  doSomething() {
    this.context.doSomething();
  }
}
<ng-container *ngIf="available$ | async">...</ng-container>

Use ProductContextAccessDirective

If access to the context is required in the template without injecting it into the component (i.e. if the component has multiple embedded contexts), the ProductContextAccessDirective can be used:

<ng-container *ngFor="let item of lineItems$ | async">
  <div class="..." ishProductContext [sku]="item.sku">
    <ng-container *ishProductContextAccess="let product = product; let context = context">
      {{ product.sku }}
      <input type="button" (click)="context.doSomething()" />
    </ng-container>
  </div>
</ng-container>

In this example, the product context is created for each item and afterwards the property product from the context is used with ishProductContextAccess and thereby made available to the embedded template.

This feature should only be used for edge cases, as it is very verbose and most of the time a proper refactoring of the embedded template into a new component can improve the code style.

Linking Embedded Contexts

There are cases where product contexts are used as meta contexts for handling add-to-cart functionality and validations thereof.
For product retail sets the surrounding product context is used as a meta context with two add-to-cart buttons (one at the detail on top, one at the button after the listing for contained items).
If those buttons are pressed, the correct amount for quantities is used to perform the add-to-cart action.
Those buttons also disable themselves if the quantity of one individual retail set part exceeds the maximum allowed order quantity.

All of this is also handled in the ProductContextFacade if the embedded contexts are initialized using ProductContextDirective and properly mapped propagateIndex.

Currently this feature is only used for enabling or disabling add-to-cart functionality, though.

Customizing Display Properties

Product contexts also contain all logic for deciding if specific functionality is available for each individual product.
Each component that handles items of this configuration checks if they are active themselves.

This functionality can be customized by changing the defaultDisplayProperties.

A more elaborate way would be to provide an ExternalDisplayPropertiesProvider.
Have a look at PunchoutProductContextDisplayPropertiesService or TactonProductContextDisplayPropertiesService for examples.

Further References

Disclaimer

The information provided in the Knowledge Base may not be applicable to all systems and situations. Intershop Communications will not be liable to any party for any direct or indirect damages resulting from the use of the Customer Support section of the Intershop Corporate Web site, including, without limitation, any lost profits, business interruption, loss of programs or other data on your information handling system.

Customer Support
Knowledge Base
Product Resources
Tickets