W3cubDocs

/Angular

Managing Data

At the end of Routing, the online store application has a product catalog with two views: a product list and product details. Users can click on a product name from the list to see details in a new view, with a distinct URL (route).

In this section, you'll create the shopping cart. You'll:

  • Update the product details page to include a "Buy" button, which adds the current product to a list of products managed by a cart service.
  • Add a cart component, which displays the items you added to your cart.
  • Add a shipping component, which retrieves shipping prices for the items in the cart by using Angular's HttpClient to retrieve shipping data from a .json file.

Services

Services are an integral part of Angular applications. In Angular, a service is an instance of a class that can be made available to any part of your application using Angular's dependency injection system.

Services are the place where you share data between parts of your application. For the online store, the cart service is where you store your cart data and methods.

Create the shopping cart service

Up to this point, users can view product information, and simulate sharing and being notified about product changes. They cannot, however, buy products.

In this section, you'll add a "Buy" button to the product details page. You'll also set up a cart service to store information about products in the cart.

Later, in the Forms part of this tutorial, this cart service also will be accessed from the page where the user checks out.

Define a cart service

  1. Generate a cart service.

    1. Right click on the app folder, choose Angular Generator, and choose Service. Name the new service cart.

      import { Injectable } from '@angular/core';
      
      @Injectable({
        providedIn: 'root'
      })
      export class CartService {
      
        constructor() {}
      
      }
    2. If the generated @Injectable() decorator does not include the { providedIn: 'root' } statement, then insert it as shown above.

  2. In the CartService class, define an items property to store the list (array) of the current products in the cart.

    export class CartService {
      items = [];
    }
  3. Define methods to add items to the cart, return cart items, and clear the cart items:

    export class CartService {
      items = [];
    
      addToCart(product) {
        this.items.push(product);
      }
    
      getItems() {
        return this.items;
      }
    
      clearCart() {
        this.items = [];
        return this.items;
      }
    }

Use the cart service

In this section, you'll update the product details component to use the cart service. You'll add a "Buy" button to the product details view. When the "Buy" button is clicked, you'll use the cart service to add the current product to the cart.

  1. Open product-details.component.ts.

  2. Set up the component to be able to use the cart service.

    1. Import the cart service.

      import { Component, OnInit } from '@angular/core';
      import { ActivatedRoute } from '@angular/router';
      
      import { products } from '../products';
      import { CartService } from '../cart.service';
    2. Inject the cart service.

      export class ProductDetailsComponent implements OnInit {
        constructor(
          private route: ActivatedRoute,
          private cartService: CartService
        ) { }
      }
  3. Define the addToCart() method, which adds the current product to the cart.

    The addToCart() method:

    • Receives the current product
    • Uses the cart service's #addToCart() method to add the product to the cart
    • Displays a message that the product has been added to the cart
    export class ProductDetailsComponent implements OnInit {
      addToCart(product) {
        window.alert('Your product has been added to the cart!');
        this.cartService.addToCart(product);
      }
    }
  4. Update the product details template to have a "Buy" button that adds the current product to the cart.

    1. Open product-details.component.html.

    2. Add a button with the label "Buy", and bind the click() event to the addToCart() method:

      <h2>Product Details</h2>
      
      <div *ngIf="product">
        <h3>{{ product.name }}</h3>
        <h4>{{ product.price | currency }}</h4>
        <p>{{ product.description }}</p>
      
        <button (click)="addToCart(product)">Buy</button>
      </div>
  5. To see the new "Buy" button, refresh the application and click on a product's name to display its details.

  6. Click the "Buy" button. The product is added to the stored list of items in the cart, and a message is displayed.

Create the cart page

At this point, users can put items in the cart by clicking "Buy", but they can't yet see their cart.

We'll create the cart page in two steps:

  1. Create a cart component and set up routing to the new component. At this point, the cart page will only have default text.
  2. Display the cart items.

Set up the component

To create the cart page, you begin by following the same steps you did to create the product details component and to set up routing for the new component.

  1. Generate a cart component, named cart.

    Reminder: In the file list, right-click the app folder, choose Angular Generator and Component.

    import { Component, OnInit } from '@angular/core';
    
    @Component({
      selector: 'app-cart',
      templateUrl: './cart.component.html',
      styleUrls: ['./cart.component.css']
    })
    export class CartComponent implements OnInit {
    
      constructor() { }
    
      ngOnInit() {
      }
    
    }
  2. Add routing (a URL pattern) for the cart component.

    Reminder: Open app.module.ts and add a route for the component CartComponent, with a path of cart:

    @NgModule({
      imports: [
        BrowserModule,
        ReactiveFormsModule,
        RouterModule.forRoot([
          { path: '', component: ProductListComponent },
          { path: 'products/:productId', component: ProductDetailsComponent },
          { path: 'cart', component: CartComponent },
        ])
      ],
  3. To see the new cart component, click the "Checkout" button. You can see the "cart works!" default text, and the URL has the pattern https://getting-started.stackblitz.io/cart, where getting-started.stackblitz.io may be different for your StackBlitz project.

    (Note: The "Checkout" button that we provided in the top-bar component was already configured with a routerLink for /cart.)

Display the cart items

Services can be used to share data across components:

  • The product details component already uses the cart service (CartService) to add products to the cart.
  • In this section, you'll update the cart component to use the cart service to display the products in the cart.
  1. Open cart.component.ts.

  2. Set up the component to be able to use the cart service. (This is the same way you set up the product details component to use the cart service, above.)

    1. Import the CartService from the cart.service.ts file.

      import { Component } from '@angular/core';
      import { CartService } from '../cart.service';
    2. Inject the CartService to manage cart information.

      export class CartComponent {
      
        constructor(
          private cartService: CartService
        ) { }
      }
  3. Define the items property to store the products in the cart.

    export class CartComponent {
      items;
    
      constructor(
        private cartService: CartService
      ) { }
    }
  4. Set the items using the cart service's getItems() method. (You defined this method when you generated cart.service.ts.)

    The resulting CartComponent class should look like this:

    export class CartComponent implements OnInit {
      items;
    
      constructor(
        private cartService: CartService
      ) { }
    
      ngOnInit() {
        this.items = this.cartService.getItems();
      }
    }
  5. Update the template with a header ("Cart"), and use a <div> with an *ngFor to display each of the cart items with its name and price.

    The resulting CartComponent template should look like this:

    <h3>Cart</h3>
    
    <div class="cart-item" *ngFor="let item of items">
      <span>{{ item.name }}</span>
      <span>{{ item.price | currency }}</span>
    </div>
  6. Test your cart component.

    1. Click on "My Store" to go to the product list page.
    2. Click on a product name to display its details.
    3. Click "Buy" to add the product to the cart.
    4. Click "Checkout" to see the cart.
    5. To add another product, click "My Store" to return to the product list. Repeat the steps above.

StackBlitz tip: Any time the preview refreshes, the cart is cleared. If you make changes to the app, the page refreshes, and you'll need to buy products again to populate the cart.

Learn more: See Introduction to Services and Dependency Injection for more information about services.

Retrieve shipping prices

Data returned from servers often takes the form of a stream. Streams are useful because they make it easy to transform the data that is returned, and to make modifications to the way data is requested. The Angular HTTP client (HttpClient) is a built-in way to fetch data from external APIs and provide them to your application as a stream.

In this section, you'll use the HTTP client to retrieve shipping prices from an external file.

Predefined shipping data

For the purpose of this Getting Started guide, we have provided shipping data in assets/shipping.json. You'll use this data to add shipping prices for items in the cart.

[
  {
    "type": "Overnight",
    "price": 25.99
  },
  {
    "type": "2-Day",
    "price": 9.99
  },
  {
    "type": "Postal",
    "price": 2.99
  }
]

Enable HttpClient for app

Before you can use Angular's HTTP client, you must set up your app to use HttpClientModule.

Angular's HttpClientModule registers the providers needed to use a single instance of the HttpClient service throughout your app. The HttpClient service is what you inject into your services to fetch data and interact with external APIs and resources.

  1. Open app.module.ts.

    This file contains imports and functionality that is available to the entire app.

  2. Import HttpClientModule from the @angular/common/http package.

    import { NgModule } from '@angular/core';
    import { BrowserModule } from '@angular/platform-browser';
    import { RouterModule } from '@angular/router';
    import { HttpClientModule } from '@angular/common/http';
  3. Add HttpClientModule to the imports array of the app module (@NgModule).

    This registers Angular's HttpClient providers globally.

    import { NgModule } from '@angular/core';
    import { BrowserModule } from '@angular/platform-browser';
    import { RouterModule } from '@angular/router';
    import { HttpClientModule } from '@angular/common/http';
    import { ReactiveFormsModule } from '@angular/forms';
    
    import { AppComponent } from './app.component';
    import { TopBarComponent } from './top-bar/top-bar.component';
    import { ProductListComponent } from './product-list/product-list.component';
    import { ProductAlertsComponent } from './product-alerts/product-alerts.component';
    import { ProductDetailsComponent } from './product-details/product-details.component';
    
    @NgModule({
      imports: [
        BrowserModule,
        HttpClientModule,
        ReactiveFormsModule,
        RouterModule.forRoot([
          { path: '', component: ProductListComponent },
          { path: 'products/:productId', component: ProductDetailsComponent },
          { path: 'cart', component: CartComponent },
        ])
      ],
      declarations: [
        AppComponent,
        TopBarComponent,
        ProductListComponent,
        ProductAlertsComponent,
        ProductDetailsComponent,
        CartComponent,
      ],
      bootstrap: [
        AppComponent
      ]
    })
    export class AppModule { }

Enable HttpClient for cart service

  1. Open cart.service.ts.

  2. Import HttpClient from the @angular/common/http package.

    import { Injectable } from '@angular/core';
    
    import { HttpClient } from '@angular/common/http';
  3. Inject HttpClient into the constructor of the CartService component class:

    export class CartService {
      items = [];
    
      constructor(
        private http: HttpClient
      ) {}
    }

Define the get() method

As you've seen, multiple components can leverage the same service. Later in this tutorial, the shipping component will use the cart service to retrieve shipping data via HTTP from the shipping.json file. Here you'll define the get() method that will be used.

  1. Continue working in cart.service.ts.

  2. Below the clearCart() method, define a new getShippingPrices() method that uses the HttpClient#get() method to retrieve the shipping data (types and prices).

    export class CartService {
      items = [];
    
      constructor(
        private http: HttpClient
      ) {}
    
      addToCart(product) {
        this.items.push(product);
      }
    
      getItems() {
        return this.items;
      }
    
      clearCart() {
        this.items = [];
        return this.items;
      }
    
      getShippingPrices() {
        return this.http.get('/assets/shipping.json');
      }
    }

Learn more: See the HttpClient guide for more information about Angular's HttpClient.

Define the shipping page

Now that your app can retrieve shipping data, you'll create a shipping component and associated template.

  1. Generate a new component named shipping.

    Reminder: In the file list, right-click the app folder, choose Angular Generator and Component.

    import { Component, OnInit } from '@angular/core';
    
    @Component({
      selector: 'app-shipping',
      templateUrl: './shipping.component.html',
      styleUrls: ['./shipping.component.css']
    })
    export class ShippingComponent implements OnInit {
    
      constructor() { }
    
      ngOnInit() {
      }
    
    }
  2. In app.module.ts, add a route for shipping. Specify a path of shipping and a component of ShippingComponent.

    @NgModule({
      imports: [
        BrowserModule,
        HttpClientModule,
        ReactiveFormsModule,
        RouterModule.forRoot([
          { path: '', component: ProductListComponent },
          { path: 'products/:productId', component: ProductDetailsComponent },
          { path: 'cart', component: CartComponent },
          { path: 'shipping', component: ShippingComponent },
        ])
      ],
      declarations: [
        AppComponent,
        TopBarComponent,
        ProductListComponent,
        ProductAlertsComponent,
        ProductDetailsComponent,
        CartComponent,
        ShippingComponent
      ],
      bootstrap: [
        AppComponent
      ]
    })
    export class AppModule { }

    The new shipping component isn't hooked into any other component yet, but you can see it in the preview pane by entering the URL specified by its route. The URL has the pattern: https://getting-started.stackblitz.io/shipping where the getting-started.stackblitz.io part may be different for your StackBlitz project.

  3. Modify the shipping component so it uses the cart service to retrieve shipping data via HTTP from the shipping.json file.

    1. Import the cart service.

      import { Component, OnInit } from '@angular/core';
      
      import { CartService } from '../cart.service';
    2. Define a shippingCosts property.

      export class ShippingComponent implements OnInit {
        shippingCosts;
      }
    3. Inject the cart service into the ShippingComponent class:

      constructor(
        private cartService: CartService
      ) {
      }
    4. Set the shippingCosts property using the getShippingPrices() method from cart service.

      export class ShippingComponent implements OnInit {
        shippingCosts;
      
        constructor(
          private cartService: CartService
        ) {
        }
      
        ngOnInit() {
          this.shippingCosts = this.cartService.getShippingPrices();
        }
      
      }
  4. Update the shipping component's template to display the shipping types and prices using async pipe:

    <h3>Shipping Prices</h3>
    
    <div class="shipping-item" *ngFor="let shipping of shippingCosts | async">
      <span>{{ shipping.type }}</span>
      <span>{{ shipping.price | currency }}</span>
    </div>
  5. Add a link from the cart page to the shipping page:

    <h3>Cart</h3>
    
    <p>
      <a routerLink="/shipping">Shipping Prices</a>
    </p>
    
    <div class="cart-item" *ngFor="let item of items">
      <span>{{ item.name }}</span>
      <span>{{ item.price | currency }}</span>
    </div>
  6. Test your shipping prices feature:

    Click on the "Checkout" button to see the updated cart. (Remember that changing the app causes the preview to refresh, which empties the cart.)

    Click on the link to navigate to the shipping prices.

Next steps

Congratulations! You have an online store application with a product catalog and shopping cart. You also have the ability to look up and display shipping prices.

To continue exploring Angular, choose either of the following options:

© 2010–2019 Google, Inc.
Licensed under the Creative Commons Attribution License 4.0.
https://angular.io/start/data