docs: edit start-data.md (#39628)

PR Close #39628
This commit is contained in:
Kapunahele Wong 2020-11-10 14:25:12 -05:00 committed by Andrew Kushnir
parent b668768c0a
commit 0870af1740
1 changed files with 112 additions and 187 deletions

View File

@ -1,57 +1,40 @@
# Managing data
At the end of [In-app Navigation](start/start-routing "Try it: In-app Navigation"), the online store application has a product catalog with two views: a product list and product details.
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.
Users can click on a product name from the list to see details in a new view, with a distinct URL, or route.
This page guides you through creating the shopping cart in three phases:
This step of the tutorial guides you through creating a shopping cart in the following phases:
* 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.
* 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.
* Add a cart component, which displays the items in the 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.
{@a services}
## Services
Services are an integral part of Angular applications. 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").
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.
{@a create-cart-service}
## 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 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").
In this section, you add a "Buy" button to the product
details view and set up a cart service to store information
about products in the cart.
Currently, users can view product information, and the application can simulate sharing and notifications about product changes.
<div class="alert is-helpful">
A later part of this tutorial, [Use forms for user input](start/start-forms "Try it: Forms for user input"), guides you through accessing this cart service from the view where the user checks out.
</div>
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.
{@a generate-cart-service}
### Define a cart service
1. To generate a cart service, right click on the `app` folder, choose `Angular Generator`, and choose `Service`. Name the new service `cart`.
1. To generate a cart service, right click on the `app` folder, choose **Angular Generator**, and choose **Service**.
Name the new service `cart`.
<code-example header="src/app/cart.service.ts" path="getting-started/src/app/cart.service.1.ts"></code-example>
<div class="alert is-helpful">
The StackBlitz generator might provide the cart service in `app.module.ts` by default. That differs from the example, which uses a bundle-optimization technique, an `@Injectable()` decorator with the `{ providedIn: 'root' }` statement.
For more information about services, see [Introduction to Services and Dependency Injection](guide/architecture-services "Concepts > Intro to Services and DI").
</div>
<code-example header="src/app/cart.service.ts" path="getting-started/src/app/cart.service.1.ts"></code-example>
1. In the `CartService` class, define an `items` property to store the array of the current products in the cart.
<code-example path="getting-started/src/app/cart.service.ts" header="src/app/cart.service.ts" region="props"></code-example>
1. Define methods to add items to the cart, return cart items, and clear the cart items:
1. Define methods to add items to the cart, return cart items, and clear the cart items.
<code-example path="getting-started/src/app/cart.service.ts" header="src/app/cart.service.ts" region="methods"></code-example>
@ -59,105 +42,83 @@ A later part of this tutorial, [Use forms for user input](start/start-forms "Try
* The `getItems()` method collects the items users add to the cart and returns each item with its associated quantity.
* The `clearCart()` method returns an empty array of items.
* The `clearCart()` method returns an empty array of items, which empties the cart.
{@a product-details-use-cart-service}
### Use the cart service
This section walks you through using the cart service to add a product to the cart with a "Buy" button.
This section walks you through using the `CartService` to add a product to the cart.
1. Open `product-details.component.ts`.
1. In `product-details.component.ts`, import the cart service.
1. Configure the component to use the cart service.
<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>
1. Import the cart service.
1. Inject the cart service by adding it to the `constructor()`.
<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 path="getting-started/src/app/product-details/product-details.component.ts" header="src/app/product-details/product-details.component.ts" region="inject-cart-service">
</code-example>
1. Inject the cart service by adding it to the `constructor()`.
<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">
</code-example>
<!--
To do: Consider defining "inject" and describing the concept of "dependency injection"
-->
1. Define the `addToCart()` method, which adds the current product to the cart.
The `addToCart()` method does the following three things:
* Receives the current `product`.
* Uses the cart service's `addToCart()` method to add the product the cart.
* Displays a message that you've added a product to the cart.
<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>
1. Update the product details template with a "Buy" button that adds the current product to the cart.
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.
1. Open `product-details.component.html`.
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.
1. Add a button with the label "Buy", and bind the `click()` event to the `addToCart()` method:
<code-example header="src/app/product-details/product-details.component.html" path="getting-started/src/app/product-details/product-details.component.html">
</code-example>
<code-example header="src/app/product-details/product-details.component.html" path="getting-started/src/app/product-details/product-details.component.html">
</code-example>
The line, `<h4>{{ product.price | currency }}</h4>`, uses the `currency` pipe to transform `product.price` from a number to a currency string.
A pipe is a way you can transform data in your HTML template.
For more information about Angular pipes, see [Pipes](guide/pipes "Pipes").
<div class="alert is-helpful">
The line, `<h4>{{ product.price | currency }}</h4>`, uses the `currency` pipe to transform `product.price` from a number to a currency string. A pipe is a way you can transform data in your HTML template. For more information about Angular pipes, see [Pipes](guide/pipes "Pipes").
</div>
1. To see the new "Buy" button, refresh the application and click on a product's name to display its details.
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.
<div class="lightbox">
<img src='generated/images/guide/start/product-details-buy.png' alt="Display details for selected product with a Buy button">
</div>
1. Click the "Buy" button to add the product to the stored list of items in the cart and display a confirmation message.
1. Click the **Buy** button to add the product to the stored list of items in the cart and display a confirmation message.
<div class="lightbox">
<img src='generated/images/guide/start/buy-alert.png' alt="Display details for selected product with a Buy button">
</div>
## Create the cart view
At this point, users can put items in the cart by clicking "Buy", but they can't yet see their cart.
For customers to see their cart, you can create the cart view in two steps:
Create the cart view in two steps:
1. Create a cart component and configure routing to the new component. At this point, the cart view has only default text.
1. Create a cart component and configure routing to the new component.
1. Display the cart items.
### Set up the component
### Set up the cart component
To create the cart view, begin by following the same steps you did to create the product details component and configure routing for the new component.
To create the cart view, follow the same steps you did to create the `ProductDetailsComponent` and configure 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`.
1. Generate a cart component named `cart` by right-clicking the `app` folder, choosing **Angular Generator**, and **Component**.
<code-example header="src/app/cart/cart.component.ts" path="getting-started/src/app/cart/cart.component.1.ts"></code-example>
1. Add routing (a URL pattern) for the cart component.
Open `app.module.ts` and add a route for the component `CartComponent`, with a `path` of `cart`:
1. Open `app.module.ts` and add a route for the component `CartComponent`, with a `path` of `cart`.
<code-example header="src/app/app.module.ts" path="getting-started/src/app/app.module.ts" region="cart-route">
</code-example>
1. Update the "Checkout" button so that it routes to the `/cart` url.
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`.
Open `top-bar.component.html` and add a `routerLink` directive pointing to `/cart`.
<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">
<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">
</code-example>
1. 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.
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.
<div class="lightbox">
<img src='generated/images/guide/start/cart-works.png' alt="Display cart view before customizing">
@ -165,83 +126,58 @@ Create the cart view in two steps:
### Display the cart items
You can use services to share data across components:
* The product details component already uses the cart service to add products to the cart.
* This section shows you how to use the cart service to display the products in the cart.
This section shows you how to use the cart service to display the products in the cart.
1. Open `cart.component.ts`.
1. In `cart.component.ts`, import the `CartService` from the `cart.service.ts` file.
1. Configure the component to use the cart service.
<code-example header="src/app/cart/cart.component.ts" path="getting-started/src/app/cart/cart.component.2.ts" region="imports">
</code-example>
1. Import the `CartService` from the `cart.service.ts` file.
1. Inject the `CartService` so that the `CartComponent` can use it by adding it to the `constructor()`.
<code-example header="src/app/cart/cart.component.ts" path="getting-started/src/app/cart/cart.component.2.ts" region="imports">
</code-example>
1. Inject the `CartService` so that the cart component can use it.
<code-example path="getting-started/src/app/cart/cart.component.2.ts" header="src/app/cart/cart.component.ts" region="inject-cart">
</code-example>
<code-example path="getting-started/src/app/cart/cart.component.2.ts" header="src/app/cart/cart.component.ts" region="inject-cart">
</code-example>
1. Define the `items` property to store the products in the cart.
<code-example path="getting-started/src/app/cart/cart.component.2.ts" header="src/app/cart/cart.component.ts" region="items">
</code-example>
1. Set the items using the cart service's `getItems()` method. Recall that you defined this method [when you generated `cart.service.ts`](#generate-cart-service).
The resulting `CartComponent` class is as follows:
1. Set the items using the `CartService` `getItems()` method.
You defined this method [when you created `cart.service.ts`](#generate-cart-service).
By using the `getItems()` method in Angular's `ngOnInit()`, Angular uses `getItems()` upon initialization of `CartComponent`.
The resulting `CartComponent` class is as follows.
<code-example path="getting-started/src/app/cart/cart.component.3.ts" header="src/app/cart/cart.component.ts" region="props-services">
</code-example>
1. Update the 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:
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.
<code-example header="src/app/cart/cart.component.html" path="getting-started/src/app/cart/cart.component.2.html" region="prices">
</code-example>
1. Test your cart component.
1. Verify that your cart works as expected:
1. Click on "My Store" to go to the product list view.
1. Click on a product name to display its details.
1. Click "Buy" to add the product to the cart.
1. Click "Checkout" to see the cart.
1. To add another product, click "My Store" to return to the product list.
Repeat to add more items to the cart.
* 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.
<div class="lightbox">
<img src='generated/images/guide/start/cart-page-full.png' alt="Cart view with products added">
</div>
<div class="alert is-helpful">
StackBlitz tip: Any time the preview refreshes, the cart is cleared. If you make changes to the app, the page refreshes, so you'll need to buy products again to populate the cart.
</div>
<div class="alert is-helpful">
For more information about services, see [Introduction to Services and Dependency Injection](guide/architecture-services "Concepts > Intro to Services and DI").
</div>
## Retrieve shipping prices
<!-- Accessing data with the HTTP client -->
Servers often return data in the form of a stream.
Streams are useful because they make it easy to transform the returned data and make modifications to the way you request that data.
The Angular HTTP client, `HttpClient`, is a built-in way to fetch data from external APIs and provide them to your app as a stream.
Angular `HttpClient` is a built-in way to fetch data from external APIs and provide them to your application as a stream.
This section shows you how to use the HTTP client to retrieve shipping prices from an external file.
### Predefined shipping data
This section shows you how to use `HttpClient` to retrieve shipping prices from an external file.
The application that StackBlitz generates for this guide comes with predefined shipping data in `assets/shipping.json`.
Use this data to add shipping prices for items in the cart.
@ -249,111 +185,98 @@ Use this data to add shipping prices for items in the cart.
<code-example header="src/assets/shipping.json" path="getting-started/src/assets/shipping.json">
</code-example>
### Configure `AppModule` to use `HttpClient`
### Use `HttpClient` in the `AppModule`
To use Angular's `HttpClient`, you must configure your application to use `HttpClientModule`.
Before you can use Angular's HTTP client, you must configure your app to use `HttpClientModule`.
Angular's `HttpClientModule` registers the providers your application needs to use the `HttpClient` service throughout your application.
Angular's `HttpClientModule` registers the providers your app needs to use a single instance of the `HttpClient` service throughout your app.
1. Open `app.module.ts`.
This file contains imports and functionality that is available to the entire app.
1. 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.
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.
<code-example header="src/app/app.module.ts" path="getting-started/src/app/app.module.ts" region="http-client-module-import">
</code-example>
1. Add `HttpClientModule` to the `AppModule` `@NgModule()` `imports` array to register Angular's `HttpClient` providers globally.
1. To register Angular's `HttpClient` providers globally, add `HttpClientModule` to the `AppModule` `@NgModule()` `imports` array.
<code-example path="getting-started/src/app/app.module.ts" header="src/app/app.module.ts" region="http-client-module">
</code-example>
### Use `HttpClient` in the cart service
### Configure `CartService` to use `HttpClient`
Now that the `AppModule` imports the `HttpClientModule`, the next step is to inject the `HttpClient` service into your service so your app can fetch data and interact with external APIs and resources.
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.
1. Open `cart.service.ts`.
1. Import `HttpClient` from the `@angular/common/http` package.
1. In `cart.service.ts`, import `HttpClient` from the `@angular/common/http` package.
<code-example header="src/app/cart.service.ts" path="getting-started/src/app/cart.service.ts" region="import-http">
</code-example>
1. Inject `HttpClient` into the `CartService` constructor:
1. Inject `HttpClient` into the `CartService` `constructor()`.
<code-example path="getting-started/src/app/cart.service.ts" header="src/app/cart.service.ts" region="inject-http">
</code-example>
### Configure `CartService` to get shipping prices
### Define the `get()` method
To get shipping data, from `shipping.json`, You can use the `HttpClient` `get()` method.
Multiple components can leverage the same service.
Later in this tutorial, the shipping component uses the cart service to retrieve shipping data via HTTP from the `shipping.json` file.
First, define a `get()` method.
1. Continue working in `cart.service.ts`.
1. Below the `clearCart()` method, define a new `getShippingPrices()` method that uses the `HttpClient` `get()` method to retrieve the shipping data.
1. In `cart.service.ts`, below the `clearCart()` method, define a new `getShippingPrices()` method that uses the `HttpClient` `get()` method.
<code-example header="src/app/cart.service.ts" path="getting-started/src/app/cart.service.ts" region="get-shipping"></code-example>
<div class="alert is-helpful">
For more information about Angular's `HttpClient`, see the [Client-Server Interaction](guide/http "Server interaction through HTTP") guide.
</div>
## Create a shipping component
## Define the shipping view
Now that you've configured your application to retrieve shipping data, you can create a place to render that data.
Now that your app can retrieve shipping data, create a shipping component and template.
1. Generate a new component named `shipping`.
Reminder: In the file list, right-click the `app` folder, choose `Angular Generator` and `Component`.
1. Generate a new component named `shipping` by right-clicking the `app` folder, choosing **Angular Generator**, and selecting **Component**.
<code-example header="src/app/shipping/shipping.component.ts" path="getting-started/src/app/shipping/shipping.component.1.ts"></code-example>
1. In `app.module.ts`, add a route for shipping. Specify a `path` of `shipping` and a component of `ShippingComponent`.
1. In `app.module.ts`, add a route for shipping.
Specify a `path` of `shipping` and a component of `ShippingComponent`.
<code-example header="src/app/app.module.ts" path="getting-started/src/app/app.module.ts" region="shipping-route"></code-example>
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.
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.
1. Modify the shipping component so that it uses the cart service to retrieve shipping data via HTTP from the `shipping.json` file.
### Configuring the `ShippingComponent` to use `CartService`
1. Import the cart service.
This section guides you through modifying the `ShippingComponent` to retrieve shipping data via HTTP from the `shipping.json` file.
<code-example header="src/app/shipping/shipping.component.ts" path="getting-started/src/app/shipping/shipping.component.ts" region="imports"></code-example>
1. In `shipping.component.ts`, import `CartService`.
1. Define a `shippingCosts` property.
<code-example header="src/app/shipping/shipping.component.ts" path="getting-started/src/app/shipping/shipping.component.ts" region="imports"></code-example>
<code-example path="getting-started/src/app/shipping/shipping.component.ts" header="src/app/shipping/shipping.component.ts" region="props"></code-example>
1. Define a `shippingCosts` property.
1. Inject the cart service in the `ShippingComponent` constructor:
<code-example path="getting-started/src/app/shipping/shipping.component.ts" header="src/app/shipping/shipping.component.ts" region="props"></code-example>
<code-example path="getting-started/src/app/shipping/shipping.component.ts" header="src/app/shipping/shipping.component.ts" region="inject-cart-service"></code-example>
1. Inject the cart service in the `ShippingComponent` `constructor()`.
1. Set the `shippingCosts` property using the `getShippingPrices()` method from the cart service.
<code-example path="getting-started/src/app/shipping/shipping.component.ts" header="src/app/shipping/shipping.component.ts" region="inject-cart-service"></code-example>
<code-example path="getting-started/src/app/shipping/shipping.component.ts" header="src/app/shipping/shipping.component.ts" region="ctor"></code-example>
1. Set the `shippingCosts` property using the `getShippingPrices()` method from the `CartService`.
1. Update the shipping component's template to display the shipping types and prices using the `async` pipe:
<code-example path="getting-started/src/app/shipping/shipping.component.ts" header="src/app/shipping/shipping.component.ts" region="ctor"></code-example>
1. Update the `ShippingComponent` template to display the shipping types and prices using the `async` pipe.
<code-example header="src/app/shipping/shipping.component.html" path="getting-started/src/app/shipping/shipping.component.html"></code-example>
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).
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).
1. Add a link from the cart view to the shipping view:
1. Add a link from the `CartComponent` view to the `ShippingComponent` view.
<code-example header="src/app/cart/cart.component.html" path="getting-started/src/app/cart/cart.component.2.html"></code-example>
1. Test your shipping prices feature:
Click the "Checkout" button to see the updated cart. Remember that changing the app causes the preview to refresh, which empties the cart.
1. Click the **Checkout** button to see the updated cart.
Remember that changing the application causes the preview to refresh, which empties the cart.
<div class="lightbox">
<img src='generated/images/guide/start/cart-empty-with-shipping-prices.png' alt="Cart with link to shipping prices">
@ -365,11 +288,13 @@ Now that your app can retrieve shipping data, create a shipping component and t
<img src='generated/images/guide/start/shipping-prices.png' alt="Display shipping prices">
</div>
<hr />
## Next steps
## What's next
Congratulations! You have an online store application with a product catalog and shopping cart. You can also look up and display shipping prices.
You now have a store application with a product catalog, a shopping cart, and you can look up shipping prices.
To continue exploring Angular, choose either of the following options:
* [Continue to the "Forms" section](start/start-forms "Try it: Forms for User Input") to finish the app by adding the shopping cart view and a checkout form.
* [Skip ahead to the "Deployment" section](start/start-deployment "Try it: Deployment") to move to local development, or deploy your app to Firebase or your own server.
To continue exploring Angular:
* 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.