Skip to content

Latest commit

 

History

History
306 lines (236 loc) · 12.5 KB

02-getting-started-products-app.md

File metadata and controls

306 lines (236 loc) · 12.5 KB

SCION Microfrontend Platform

SCION Microfrontend Platform Projects Overview Changelog Contributing Sponsoring

SCION Microfrontend Platform > Getting Started > Create Products Application

The products micro app provides two microfrontends, the ProductList Microfrontend that lists our products, and the Product Microfrontend that displays a product.


  • Project directory:
    scion-microfrontend-platform-getting-started/products-app
  • Installing modules (if not already done):
    npm run install
  • Starting the app:
    npm run start
  • Opening the app in the browser:
    http://localhost:4201

Prerequisites

If you checked out the skeleton branch of the Git repository for this guide, the directory structure should look like this. If not, please refer to How to complete this guide for step-by-step instructions.

   scion-microfrontend-platform-getting-started
   ├── products-app
   │   ├── src
   │   │   ├── product // Product Microfrontend
   │   │   │    ├── product.html
   │   │   │    ├── product.ts
   │   │   │    └── product.scss
   │   │   ├── product-list  // ProductList Microfrontend
   │   │   │    ├── product-list.html
   │   │   │    ├── product-list.ts
   │   │   │    └── product-list.scss
   │   │   ├── index.html
   │   │   ├── product.data.json // Sample data
   │   │   ├── product.service.ts // Service to access sample data
   │   │   └── query-params.ts
   │   ├── package.json
   │   └── tsconfig.json

Follow the following instructions to get the Products App running.

Start the *Products App*

Run npm run start to start the application. Then open the page http://localhost:4201 in your browser. You should see two links to open the ProductList Microfrontend and Product Microfrontend. When you click on a link, the particular microfrontend opens, but does not show much yet, only its title.

By the end of this chapter, the ProductList Microfrontend will list our products. When clicking on a product link, we can navigate to the Product Microfrontend to see details about the product.

Implement the *ProductList Microfrontend*

In this section, we will implement the ProductList Microfrontend that lists our products.

  1. Open the HTML template products-app/src/product-list/product-list.html.

  2. After the <h1> element, add a section to display our products, as follows:

          <body>
            <h1>Products</h1>
    [+]     <section id="products"></section>
          </body> 
  3. Open the TypeScript file products-app/src/product-list/product-list.ts and add the following method after the init method. This method will render products of given IDs.

          import {ProductService} from '../product.service';
    
          public render(ids?: string[]): void {
            const productsSection = document.querySelector('section#products');
            productsSection.innerHTML = null;
          
            ProductService.INSTANCE.getProducts({ids}).forEach(product => {
              // Product Name
              const productLink = productsSection.appendChild(document.createElement('a'));
              productLink.innerText = product.name;
              productLink.href = `/product/product.html#?id=${product.id}`;
          
              // Product Price
              productsSection.appendChild(document.createTextNode(`$ ${product.price.toFixed(2)}`));
            });
          }

    We need a reference to the <section> element that we added to the template in the previous step. Our products will be added to this section. Since the render method is called every time the products to be displayed change, we clear the section's content first. Then, using the ProductService, we query the products of given IDs. For each product, we create an anchor element, that when clicked, navigates to the Product Microfrontend located at /product/product.html. We pass the ID of the product in the form of a query parameter. Note that we added the query parameter to the URL's fragment part, that is after the hash (#), so that the page is not reloaded when the query parameter is changed. This is similar to hash-based routing, but it only applies to query parameters. Finally, after the link, we append a text node to display the price of the product.

  4. In the init method, subscribe to query parameter changes and invoke the render method, passing the ids as argument. The ids query parameter contains the IDs of the products to be displayed as a comma-separated list.

          import {ProductService} from '../product.service';
    [+]   import {QueryParams} from '../query-params';
    
          public async init(): Promise<void> {
    [+]     QueryParams.observe$.subscribe(queryParams => {
    [+]       const productIds = queryParams.get('ids')?.split(',');
    [+]       this.render(productIds);
    [+]     });
          }
Implement the *Product Microfrontend*

In this section, we will implement the Product Microfrontend to display a product.

  1. Open the HTML template products-app/src/product/product.html.

  2. After the <h1> element, add a section to display the product, as follows:

          <body>
            <h1>Product</h1>
    [+]     <section id="product"></section>
          </body> 
  3. Open the TypeScript file products-app/src/product/product.ts.

    Add a render method after the init method to render the product of given ID, as follows:

          import {ProductService} from '../product.service';
    
          public render(productId: string): void {
            const productSection = document.querySelector('section#product');
            const product = ProductService.INSTANCE.getProduct(productId);
          
            productSection.innerHTML = null;
          
            // Name
            productSection.appendChild(document.createElement('label')).innerText = 'Name:';
            productSection.appendChild(document.createTextNode(product.name));
          
            // Price
            productSection.appendChild(document.createElement('label')).innerText = 'Price:';
            productSection.appendChild(document.createTextNode(`$ ${product.price.toFixed(2)}`));
          }

    We need a reference to the <section> element that we added to the template in the previous section. The product will be added to this section. Since the render method is called every time the product to be displayed change, we clear the section's content first. Finally, using the ProductService, we look up the product of given ID and display its name and price.

  4. In the init method, subscribe to query parameter changes and invoke the render method, passing the id as argument. The id query parameter contains the ID of the product to be displayed.

          import {ProductService} from '../product.service';
    [+]   import {QueryParams} from '../query-params';
    
          public async init(): Promise<void> {
    [+]     QueryParams.observe$.subscribe(queryParams => this.render(queryParams.get('id')));
          }
Open the app in the browser

We did it! Run npm run start to serve the applications.

When you open the page http://localhost:4200 in your browser and click the Products button, you will see the ProductList Microfrontend. When clicking on a product, the Product Microfrontend opens, displaying information about the product. So far, the Product Microfrontend replaces the ProductList Microfrontend. In a subsequent chapter, we will display the product to the right of the product list in the aside router outlet.

What we did in this chapter

In this chapter, we have implemented the ProductList Microfrontend and Product Microfrontend of the Products App.

The products-app/src/product-list/product-list.html looks as following:
<!DOCTYPE html>
<html lang="en">
  <head>
    <title>Products</title>
    <link rel="stylesheet" type="text/css" href="product-list.scss">
    <script type="module" src="./product-list.ts"></script>
  </head>
  <body>
    <h1>Products</h1>
    <section id="products"></section>
  </body>
</html>
The products-app/src/product-list/product-list.ts looks as following:
import {ProductService} from '../product.service';
import {QueryParams} from '../query-params';

class ProductListController {

  public async init(): Promise<void> {
    QueryParams.observe$.subscribe(queryParams => {
      const productIds = queryParams.get('ids')?.split(',');
      this.render(productIds);
    });
  }

  public render(ids?: string[]): void {
    const productsSection = document.querySelector('section#products');
    productsSection.innerHTML = null;

    ProductService.INSTANCE.getProducts({ids}).forEach(product => {
      // Product Name
      const productLink = productsSection.appendChild(document.createElement('a'));
      productLink.innerText = product.name;
      productLink.href = `/product/product.html#id=${product.id}`;

      // Product Price
      productsSection.appendChild(document.createTextNode(`$ ${product.price.toFixed(2)}`));
    });
  }
}

new ProductListController().init();
The products-app/src/product/product.html looks as following:
<!DOCTYPE html>
<html lang="en">
  <head>
    <title>Product</title>
    <link rel="stylesheet" type="text/css" href="product.scss">
    <script type="module" src="./product.ts"></script>
  </head>
  <body>
    <h1>Product</h1>
    <section id="product"></section>
  </body>
</html>
The products-app/src/product/product.ts looks as following:
import {ProductService} from '../product.service';
import {QueryParams} from '../query-params';

class ProductController {

  public async init(): Promise<void> {
    QueryParams.observe$.subscribe(queryParams => this.render(queryParams.get('id')));
  }

  public render(productId: string): void {
    const productSection = document.querySelector('section#product');
    const product = ProductService.INSTANCE.getProduct(productId);

    productSection.innerHTML = null;

    // Name
    productSection.appendChild(document.createElement('label')).innerText = 'Name:';
    productSection.appendChild(document.createTextNode(product.name));

    // Price
    productSection.appendChild(document.createElement('label')).innerText = 'Price:';
    productSection.appendChild(document.createTextNode(`$ ${product.price.toFixed(2)}`));
  }
}

new ProductController().init();
What's next

In the next chapter, we will develop the Customers App. Click here to continue.