2020-09-17 13:10:16 -04:00
# Managing data
2019-03-20 11:10:47 -04:00
2020-11-10 14:25:12 -05:00
This guide builds on the second step of the [Getting started with a basic Angular application ](start ) tutorial, [Adding navigation ](start/start-routing "Adding navigation" ).
At this stage of development, the store application has a product catalog with two views: a product list and product details.
2019-09-20 16:22:58 -04:00
Users can click on a product name from the list to see details in a new view, with a distinct URL, or route.
2019-03-20 11:10:47 -04:00
2020-11-10 14:25:12 -05:00
This step of the tutorial guides you through creating a shopping cart in the following phases:
2019-09-24 15:23:24 -04:00
2020-11-10 14:25:12 -05:00
* Update the product details view to include a **Buy** button, which adds the current product to a list of products that a cart service manages.
2019-09-20 16:22:58 -04:00
* Add a cart component, which displays the items in the cart.
2019-05-30 08:01:19 -04:00
* 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.
2019-03-20 11:10:47 -04:00
{@a create-cart-service}
2020-11-10 14:25:12 -05:00
## Create the shopping cart service
2019-03-20 11:10:47 -04:00
2020-11-10 14:25:12 -05:00
In Angular, a service is an instance of a class that you can make available to any part of your application using Angular's [dependency injection system ](guide/glossary#dependency-injection-di "Dependency injection definition" ).
2019-03-20 11:10:47 -04:00
2020-11-10 14:25:12 -05:00
Currently, users can view product information, and the application can simulate sharing and notifications about product changes.
2019-03-20 11:10:47 -04:00
2020-11-10 14:25:12 -05:00
The next step is to build a way for users to add products to a cart.
This section walks you through adding a **Buy** button and setting up a cart service to store information about products in the cart.
2019-03-20 11:10:47 -04:00
{@a generate-cart-service}
2020-11-10 14:25:12 -05:00
### Define a cart service
2020-02-18 13:14:48 -05:00
2020-11-10 14:25:12 -05:00
1. To generate a cart service, right click on the `app` folder, choose **Angular Generator** , and choose **Service** .
Name the new service `cart` .
2020-02-18 13:14:48 -05:00
2020-11-10 14:25:12 -05:00
< code-example header = "src/app/cart.service.ts" path = "getting-started/src/app/cart.service.1.ts" > < / code-example >
2019-03-20 11:10:47 -04:00
2019-09-20 16:22:58 -04:00
1. In the `CartService` class, define an `items` property to store the array of the current products in the cart.
2019-03-20 11:10:47 -04:00
2019-09-20 16:22:58 -04:00
< code-example path = "getting-started/src/app/cart.service.ts" header = "src/app/cart.service.ts" region = "props" > < / code-example >
2019-03-20 11:10:47 -04:00
2020-11-10 14:25:12 -05:00
1. Define methods to add items to the cart, return cart items, and clear the cart items.
2019-03-20 11:10:47 -04:00
2019-09-20 16:22:58 -04:00
< code-example path = "getting-started/src/app/cart.service.ts" header = "src/app/cart.service.ts" region = "methods" > < / code-example >
2019-03-20 11:10:47 -04:00
2019-07-20 13:40:17 -04:00
* The `addToCart()` method appends a product to an array of `items` .
2019-03-20 11:10:47 -04:00
2019-09-20 16:22:58 -04:00
* The `getItems()` method collects the items users add to the cart and returns each item with its associated quantity.
2019-03-20 11:10:47 -04:00
2020-11-10 14:25:12 -05:00
* The `clearCart()` method returns an empty array of items, which empties the cart.
2019-03-20 11:10:47 -04:00
{@a product-details-use-cart-service}
2020-11-10 14:25:12 -05:00
### Use the cart service
2019-03-20 11:10:47 -04:00
2020-11-10 14:25:12 -05:00
This section walks you through using the `CartService` to add a product to the cart.
2019-03-20 11:10:47 -04:00
2020-11-10 14:25:12 -05:00
1. In `product-details.component.ts` , import the cart service.
2019-03-20 11:10:47 -04:00
2020-11-10 14:25:12 -05:00
< code-example header = "src/app/product-details/product-details.component.ts" path = "getting-started/src/app/product-details/product-details.component.ts" region = "cart-service" >
< / code-example >
2019-03-20 11:10:47 -04:00
2020-11-10 14:25:12 -05:00
1. Inject the cart service by adding it to the `constructor()` .
2019-03-20 11:10:47 -04:00
2020-11-10 14:25:12 -05:00
< code-example path = "getting-started/src/app/product-details/product-details.component.ts" header = "src/app/product-details/product-details.component.ts" region = "inject-cart-service" >
2019-03-20 11:10:47 -04:00
< / code-example >
2019-07-20 13:40:17 -04:00
1. Define the `addToCart()` method, which adds the current product to the cart.
2019-03-20 11:10:47 -04:00
2019-09-20 16:22:58 -04:00
< code-example path = "getting-started/src/app/product-details/product-details.component.ts" header = "src/app/product-details/product-details.component.ts" region = "add-to-cart" > < / code-example >
2019-03-20 11:10:47 -04:00
2020-11-10 14:25:12 -05:00
The `addToCart()` method does the following:
* Takes the current `product` as an argument.
* Uses the `CartService` `addToCart()` method to add the product the cart.
* Displays a message that you've added a product to the cart.
2020-08-11 07:50:38 -04:00
2020-11-10 14:25:12 -05:00
1. In `product-details.component.html` , add a button with the label **Buy** , and bind the `click()` event to the `addToCart()` method.
This code updates the product details template with a **Buy** button that adds the current product to the cart.
2020-04-14 22:15:48 -04:00
2020-11-10 14:25:12 -05:00
< code-example header = "src/app/product-details/product-details.component.html" path = "getting-started/src/app/product-details/product-details.component.html" >
< / code-example >
2020-04-14 22:15:48 -04:00
2020-11-10 14:25:12 -05:00
1. Verify that the new **Buy** button appears as expected by refreshing the application and clicking on a product's name to display its details.
2019-03-20 11:10:47 -04:00
2019-11-11 17:47:51 -05:00
< div class = "lightbox" >
< img src = 'generated/images/guide/start/product-details-buy.png' alt = "Display details for selected product with a Buy button" >
< / div >
2019-07-20 13:40:17 -04:00
2020-11-10 14:25:12 -05:00
1. Click the **Buy** button to add the product to the stored list of items in the cart and display a confirmation message.
2019-03-20 11:10:47 -04:00
2019-11-11 17:47:51 -05:00
< div class = "lightbox" >
< img src = 'generated/images/guide/start/buy-alert.png' alt = "Display details for selected product with a Buy button" >
< / div >
2019-03-20 11:10:47 -04:00
2020-02-18 13:14:48 -05:00
## Create the cart view
2019-03-20 11:10:47 -04:00
2020-11-10 14:25:12 -05:00
For customers to see their cart, you can create the cart view in two steps:
2019-03-20 11:10:47 -04:00
2020-11-10 14:25:12 -05:00
1. Create a cart component and configure routing to the new component.
2019-07-20 13:40:17 -04:00
1. Display the cart items.
2019-03-20 11:10:47 -04:00
2020-11-10 14:25:12 -05:00
### Set up the cart component
2019-03-20 11:10:47 -04:00
2020-11-10 14:25:12 -05:00
To create the cart view, follow the same steps you did to create the `ProductDetailsComponent` and configure routing for the new component.
2019-03-20 11:10:47 -04:00
2020-11-10 14:25:12 -05:00
1. Generate a cart component named `cart` by right-clicking the `app` folder, choosing **Angular Generator** , and **Component** .
2019-03-20 11:10:47 -04:00
< code-example header = "src/app/cart/cart.component.ts" path = "getting-started/src/app/cart/cart.component.1.ts" > < / code-example >
2020-11-13 16:09:26 -05:00
StackBlitz also generates an `ngOnInit()` by default in components. You can ignore the `CartComponent` `ngOnInit()` for this tutorial.
2020-11-10 14:25:12 -05:00
1. Open `app.module.ts` and add a route for the component `CartComponent` , with a `path` of `cart` .
2019-03-20 11:10:47 -04:00
< code-example header = "src/app/app.module.ts" path = "getting-started/src/app/app.module.ts" region = "cart-route" >
< / code-example >
2020-11-10 14:25:12 -05:00
1. Update the **Checkout** button so that it routes to the `/cart` URL.
In `top-bar.component.html` , add a `routerLink` directive pointing to `/cart` .
2019-03-20 11:10:47 -04:00
2020-11-10 14:25:12 -05:00
< code-example header = "src/app/top-bar/top-bar.component.html" path = "getting-started/src/app/top-bar/top-bar.component.html" region = "cart-route" >
2020-03-09 05:34:41 -04:00
< / code-example >
2019-09-20 16:22:58 -04:00
2020-11-10 14:25:12 -05:00
1. Verify the new `CartComponent` works as expected by clicking 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.
2019-03-20 11:10:47 -04:00
2019-11-11 17:47:51 -05:00
< div class = "lightbox" >
2020-02-18 13:14:48 -05:00
< img src = 'generated/images/guide/start/cart-works.png' alt = "Display cart view before customizing" >
2019-11-11 17:47:51 -05:00
< / div >
2019-03-20 11:10:47 -04:00
2019-07-20 13:40:17 -04:00
### Display the cart items
2019-03-20 11:10:47 -04:00
2020-11-10 14:25:12 -05:00
This section shows you how to use the cart service to display the products in the cart.
2019-03-20 11:10:47 -04:00
2020-11-10 14:25:12 -05:00
1. In `cart.component.ts` , import the `CartService` from the `cart.service.ts` file.
2019-03-20 11:10:47 -04:00
2020-11-10 14:25:12 -05:00
< code-example header = "src/app/cart/cart.component.ts" path = "getting-started/src/app/cart/cart.component.2.ts" region = "imports" >
< / code-example >
2019-03-20 11:10:47 -04:00
2020-11-10 14:25:12 -05:00
1. Inject the `CartService` so that the `CartComponent` can use it by adding it to the `constructor()` .
2019-03-20 11:10:47 -04:00
2020-11-10 14:25:12 -05:00
< code-example path = "getting-started/src/app/cart/cart.component.2.ts" header = "src/app/cart/cart.component.ts" region = "inject-cart" >
< / code-example >
2019-03-20 11:10:47 -04:00
1. Define the `items` property to store the products in the cart.
2019-09-20 16:22:58 -04:00
< code-example path = "getting-started/src/app/cart/cart.component.2.ts" header = "src/app/cart/cart.component.ts" region = "items" >
2019-03-20 11:10:47 -04:00
< / code-example >
2020-11-13 16:09:26 -05:00
This code sets the items using the `CartService` `getItems()` method.
2020-11-10 14:25:12 -05:00
You defined this method [when you created `cart.service.ts` ](#generate-cart-service ).
2019-03-20 11:10:47 -04:00
2020-11-10 14:25:12 -05:00
1. Update the cart template with a header, and use a `<div>` with an `*ngFor` to display each of the cart items with its name and price.
The resulting `CartComponent` template is as follows.
2019-03-20 11:10:47 -04:00
< code-example header = "src/app/cart/cart.component.html" path = "getting-started/src/app/cart/cart.component.2.html" region = "prices" >
< / code-example >
2020-11-10 14:25:12 -05:00
1. Verify that your cart works as expected:
2019-03-20 11:10:47 -04:00
2020-11-10 14:25:12 -05:00
* Click **My Store**
* Click on a product name to display its details.
* Click **Buy** to add the product to the cart.
* Click **Checkout** to see the cart.
2019-03-20 11:10:47 -04:00
2019-11-11 17:47:51 -05:00
< div class = "lightbox" >
2020-02-18 13:14:48 -05:00
< img src = 'generated/images/guide/start/cart-page-full.png' alt = "Cart view with products added" >
2019-11-11 17:47:51 -05:00
< / div >
2019-03-20 11:10:47 -04:00
2020-02-18 13:14:48 -05:00
For more information about services, see [Introduction to Services and Dependency Injection ](guide/architecture-services "Concepts > Intro to Services and DI" ).
2019-03-20 11:10:47 -04:00
## Retrieve shipping prices
2019-09-20 16:22:58 -04:00
Servers often return data in the form of a stream.
2020-08-30 12:54:11 -04:00
Streams are useful because they make it easy to transform the returned data and make modifications to the way you request that data.
2020-11-10 14:25:12 -05:00
Angular `HttpClient` is a built-in way to fetch data from external APIs and provide them to your application as a stream.
2019-03-20 11:10:47 -04:00
2020-11-10 14:25:12 -05:00
This section shows you how to use `HttpClient` to retrieve shipping prices from an external file.
2019-03-20 11:10:47 -04:00
2020-02-11 02:41:55 -05:00
The application that StackBlitz generates for this guide comes with predefined shipping data in `assets/shipping.json` .
2019-09-20 16:22:58 -04:00
Use this data to add shipping prices for items in the cart.
2019-03-20 11:10:47 -04:00
< code-example header = "src/assets/shipping.json" path = "getting-started/src/assets/shipping.json" >
< / code-example >
2020-11-10 14:25:12 -05:00
### Configure `AppModule` to use `HttpClient`
2019-03-20 11:10:47 -04:00
2020-11-10 14:25:12 -05:00
To use Angular's `HttpClient` , you must configure your application to use `HttpClientModule` .
2019-03-20 11:10:47 -04:00
2020-11-10 14:25:12 -05:00
Angular's `HttpClientModule` registers the providers your application needs to use the `HttpClient` service throughout your application.
2019-03-20 11:10:47 -04:00
2020-11-10 14:25:12 -05:00
1. In `app.module.ts` , import `HttpClientModule` from the `@angular/common/http` package at the top of the file with the other imports.
As there are a number of other imports, this code snippet omits them for brevity.
Be sure to leave the existing imports in place.
2019-03-20 11:10:47 -04:00
< code-example header = "src/app/app.module.ts" path = "getting-started/src/app/app.module.ts" region = "http-client-module-import" >
< / code-example >
2020-11-10 14:25:12 -05:00
1. To register Angular's `HttpClient` providers globally, add `HttpClientModule` to the `AppModule` `@NgModule()` `imports` array.
2019-03-20 11:10:47 -04:00
2019-09-20 16:22:58 -04:00
< code-example path = "getting-started/src/app/app.module.ts" header = "src/app/app.module.ts" region = "http-client-module" >
2019-03-20 11:10:47 -04:00
< / code-example >
2020-11-10 14:25:12 -05:00
### Configure `CartService` to use `HttpClient`
2019-03-20 11:10:47 -04:00
2020-11-10 14:25:12 -05:00
The next step is to inject the `HttpClient` service into your service so your application can fetch data and interact with external APIs and resources.
2019-03-20 11:10:47 -04:00
2020-11-10 14:25:12 -05:00
1. In `cart.service.ts` , import `HttpClient` from the `@angular/common/http` package.
2019-03-20 11:10:47 -04:00
< code-example header = "src/app/cart.service.ts" path = "getting-started/src/app/cart.service.ts" region = "import-http" >
< / code-example >
2020-11-10 14:25:12 -05:00
1. Inject `HttpClient` into the `CartService` `constructor()` .
2019-03-20 11:10:47 -04:00
2019-09-20 16:22:58 -04:00
< code-example path = "getting-started/src/app/cart.service.ts" header = "src/app/cart.service.ts" region = "inject-http" >
2019-03-20 11:10:47 -04:00
< / code-example >
2020-11-10 14:25:12 -05:00
### Configure `CartService` to get shipping prices
2019-03-20 11:10:47 -04:00
2020-11-10 14:25:12 -05:00
To get shipping data, from `shipping.json` , You can use the `HttpClient` `get()` method.
2019-03-20 11:10:47 -04:00
2020-11-10 14:25:12 -05:00
1. In `cart.service.ts` , below the `clearCart()` method, define a new `getShippingPrices()` method that uses the `HttpClient` `get()` method.
2019-03-20 11:10:47 -04:00
< code-example header = "src/app/cart.service.ts" path = "getting-started/src/app/cart.service.ts" region = "get-shipping" > < / code-example >
2020-02-18 13:14:48 -05:00
For more information about Angular's `HttpClient` , see the [Client-Server Interaction ](guide/http "Server interaction through HTTP" ) guide.
2019-03-20 11:10:47 -04:00
2020-11-10 14:25:12 -05:00
## Create a shipping component
2019-03-20 11:10:47 -04:00
2020-11-10 14:25:12 -05:00
Now that you've configured your application to retrieve shipping data, you can create a place to render that data.
2019-03-20 11:10:47 -04:00
2020-11-10 14:25:12 -05:00
1. Generate a new component named `shipping` by right-clicking the `app` folder, choosing **Angular Generator** , and selecting **Component** .
2019-07-20 13:40:17 -04:00
2019-03-20 11:10:47 -04:00
< code-example header = "src/app/shipping/shipping.component.ts" path = "getting-started/src/app/shipping/shipping.component.1.ts" > < / code-example >
2020-11-10 14:25:12 -05:00
1. In `app.module.ts` , add a route for shipping.
Specify a `path` of `shipping` and a component of `ShippingComponent` .
2019-03-20 11:10:47 -04:00
< code-example header = "src/app/app.module.ts" path = "getting-started/src/app/app.module.ts" region = "shipping-route" > < / code-example >
2020-11-10 14:25:12 -05:00
There's no link to the new shipping component yet, but you can see its template in the preview pane by entering the URL its route specifies.
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.
2019-03-20 11:10:47 -04:00
2020-11-10 14:25:12 -05:00
### Configuring the `ShippingComponent` to use `CartService`
2019-03-20 11:10:47 -04:00
2020-11-10 14:25:12 -05:00
This section guides you through modifying the `ShippingComponent` to retrieve shipping data via HTTP from the `shipping.json` file.
2019-03-20 11:10:47 -04:00
2020-11-10 14:25:12 -05:00
1. In `shipping.component.ts` , import `CartService` .
2019-03-20 11:10:47 -04:00
2020-11-10 14:25:12 -05:00
< code-example header = "src/app/shipping/shipping.component.ts" path = "getting-started/src/app/shipping/shipping.component.ts" region = "imports" > < / code-example >
2019-03-20 11:10:47 -04:00
2020-11-10 14:25:12 -05:00
1. Inject the cart service in the `ShippingComponent` `constructor()` .
2019-03-20 11:10:47 -04:00
2020-11-10 14:25:12 -05:00
< code-example path = "getting-started/src/app/shipping/shipping.component.ts" header = "src/app/shipping/shipping.component.ts" region = "inject-cart-service" > < / code-example >
2019-03-20 11:10:47 -04:00
2020-11-13 16:09:26 -05:00
1. Define a `shippingCosts` property that sets the `shippingCosts` property using the `getShippingPrices()` method from the `CartService` .
2019-03-20 11:10:47 -04:00
2020-11-13 16:09:26 -05:00
< code-example path = "getting-started/src/app/shipping/shipping.component.ts" header = "src/app/shipping/shipping.component.ts" region = "props" > < / code-example >
2020-11-10 14:25:12 -05:00
1. Update the `ShippingComponent` template to display the shipping types and prices using the `async` pipe.
2019-03-20 11:10:47 -04:00
< code-example header = "src/app/shipping/shipping.component.html" path = "getting-started/src/app/shipping/shipping.component.html" > < / code-example >
2020-11-10 14:25:12 -05:00
The `async` pipe returns the latest value from a stream of data and continues to do so for the life of a given component.
When Angular destroys that component, the `async` pipe automatically stops.
For detailed information about the `async` pipe, see the [AsyncPipe API documentation ](/api/common/AsyncPipe ).
2019-03-20 11:10:47 -04:00
2020-11-10 14:25:12 -05:00
1. Add a link from the `CartComponent` view to the `ShippingComponent` view.
2019-03-20 11:10:47 -04:00
< code-example header = "src/app/cart/cart.component.html" path = "getting-started/src/app/cart/cart.component.2.html" > < / code-example >
2020-11-10 14:25:12 -05:00
1. Click the **Checkout** button to see the updated cart.
Remember that changing the application causes the preview to refresh, which empties the cart.
2019-03-20 11:10:47 -04:00
2019-11-11 17:47:51 -05:00
< div class = "lightbox" >
< img src = 'generated/images/guide/start/cart-empty-with-shipping-prices.png' alt = "Cart with link to shipping prices" >
< / div >
2019-03-20 11:10:47 -04:00
Click on the link to navigate to the shipping prices.
2019-11-11 17:47:51 -05:00
< div class = "lightbox" >
< img src = 'generated/images/guide/start/shipping-prices.png' alt = "Display shipping prices" >
< / div >
2019-03-20 11:10:47 -04:00
2020-11-10 14:25:12 -05:00
< hr / >
## What's next
2019-03-20 11:10:47 -04:00
2020-11-10 14:25:12 -05:00
You now have a store application with a product catalog, a shopping cart, and you can look up shipping prices.
2019-03-20 11:10:47 -04:00
2020-11-10 14:25:12 -05:00
To continue exploring Angular:
2019-03-20 11:10:47 -04:00
2020-11-10 14:25:12 -05:00
* Continue to [Forms for User Input ](start/start-forms "Forms for User Input" ) to finish the application by adding the shopping cart view and a checkout form.
* Skip ahead to [Deployment ](start/start-deployment "Deployment" ) to move to local development, or deploy your application to Firebase or your own server.