Reactive element - A list of Product Items with components

Concrete example of a product card implemented with Potions framework
profile photo
Julien Vinckel

ProductItem component

We can see how a cell can be transformed to a product just by replacing the reference by a product_id. We can then imagine a method to retrieve the full product with a product_title a product_price and a product_img_src.
javascript
import { PotionsProductItem } from "./PotionsProductItem.js"; import { of, delay, share } from "rxjs"; window.potions = { getProduct: product_id => { return of({ id: product_id, title: "Super produit", img_src: "https://upload.wikimedia.org/wikipedia/commons/thumb/d/d7/Monastyr_Karmelitiv_Bosykh_panorama.jpg/800px-Monastyr_Karmelitiv_Bosykh_panorama.jpg", price: "10" }).pipe(delay(2000)); } }; customElements.define("potions-product-item", PotionsProductItem);
index.js
javascript
import { Component } from "./Component.js"; import { switchMap } from "rxjs"; export class PotionsProductItem extends Component { static get observedAttributes() { return ["product_id"]; } connectedCallback() { super.connectedCallback(); this.state$ = super.observedAttributes$.pipe( switchMap(observedAttributes => { return window.potions.getProduct(observedAttributes["product_id"]); }) ); } templateStyle(state) { return ` <style> :host { display:flex; border: 1px solid black; padding:20px; margin:10px; justify-content:center; } </style>`; } template(product) { return product ? `<div> <div>${product.id}<div> <img src="${product.img_src}"></img> <div>${product.title}<div> <div>${product.price}<div> </div> ` : ""; } }
PotionsProductItem.js

PotionsProductList

So we change
javascript
<!DOCTYPE html> <link rel="shortcut icon" href="#" /> <html lang="fr"> <body> <potions-product-list product_list_id="list_1"></potions-product-list> <script src="main.js"></script> </body> </html>
index.html
javascript
import { PotionsProductItem } from "./PotionsProductItem.js"; import { PotionsProductList } from "./PotionsProductList.js"; import { of, delay, share } from "rxjs"; window.potions = { getProductList: product_list_id => { return of({ id: product_list_id, products: ["1", "2", "3"] }).pipe( delay(2000) ); }, getProduct: product_id => { return of({ id: product_id, title: "Super produit", img_src: "https://upload.wikimedia.org/wikipedia/commons/thumb/d/d7/Monastyr_Karmelitiv_Bosykh_panorama.jpg/800px-Monastyr_Karmelitiv_Bosykh_panorama.jpg", price: "10" }).pipe(delay(2000)); } }; customElements.define("potions-product-list", PotionsProductList); customElements.define("potions-product-item", PotionsProductItem);
index.js
javascript
import { Component } from "./Component.js"; import { switchMap, map } from "rxjs"; export class PotionsProductList extends Component { static get observedAttributes() { return ["product_list_id"]; } connectedCallback() { super.connectedCallback(); this.state$ = super.observedAttributes$.pipe( switchMap(observedAttributes => { return window.potions.getProductList( observedAttributes["product_list_id"] ); }) ); } templateStyle(state) { return ` <style> :host { display:flex; padding:20px; margin:10px; justify-content:center; flex-direction:column; } .list { display:flex; flex-direction:row; } </style>`; } template(list) { if (list) { const product_items = list.products .map( product_id => `<potions-product-item product_id="${product_id}"></potions-product-item>` ) .reduce( (previousValue, currentValue) => `${previousValue} ${currentValue}`, "" ); return `<div> <div> ${list.id} </div> <div class="list"> ${product_items} </div> </div>`; } else { return ""; } } }
PotionsProductList
Related posts
post image
Potions Reactive Elements
Example
With custom components
Example of a way to link a component custom element to an RxJS state
post image
Creating a new query language specialized in event processing
post image
The actor model - trick to never complete the channel
Powered by Notaku