- Lab
-
Libraries: If you want this lab, consider one of these libraries.
- Core Tech
Guided: Angular Foundations
Imagine you've just joined a development team maintaining an e-commerce website that sells robot parts. The site is functional, but it lacks key functionality and features. Your mission? To dive into the codebase and make strategic improvements to enhance the user experience—all while mastering essential Angular concepts. In this hands-on lab, you’ll work with a pre-existing application consisting of a catalog page and cart page. Along the way, you'll practice creating new components, adding routing and app routes, linking to components/pages, repeating data with for loops, passing data to components with input properties, and creating and consuming services. Each step will guide you through modifying the application, reinforcing Angular fundamentals in a practical, real-world scenario. By the end of the lab, you won’t just understand Angular—you’ll have applied it, gaining the necessary skills to start building your own dynamic web applications! Your robot parts store awaits its transformation—are you ready to take it to the next level?
Lab Info
Table of Contents
-
Challenge
Introduction
In this Angular guided lab, you'll be working with the Joe's Robot Shop application. The app is currently functional but missing key features.
To see its current rudimentary state:
- Click the Run button in the Terminal tab in the bottom-right.
- Then, click either the Web Browser tab to the right, or click on this link to open the app in a new browser tab: {{localhost:4200}}.
You'll notice that it currently displays a simple Catalog page with only one hard-coded product. There's currently no way to display multiple products, add items to a cart, or navigate to a Cart page.
What You'll Work On:
In this lab, you'll implement various features including:
- Adding and navigating to routes
- Using the Angular CLI to generate components
- Passing data to child components
- Repeating elements with
@for - Creating and injecting services
- Managing cart state with Angular state management
Solution Directory and Validation
As you work through each step, tasks can be validated by clicking on the Validate button. If you're stuck or would like to compare solutions, a
/solutionfolder has been provided for you.
Before You Get Started
If you haven't already, click the Run button in the Terminal tab, then go ahead and continue to the next step.
-
Challenge
Add Routing to Your App
You are starting with a working Angular application, but the app currently has no routing.
Notice that the
Appcomponent template (src/app/app.html) has the<bot-catalog />component hard-coded in its HTML. As it stands, to display a different component, you'd have to manually edit theAppcomponent template.To add routing so pages load dynamically based on the URL:
- Define routes for the Catalog and Cart pages in a new
app.routes.tsfile. - Then, provide those routes in the
app.config.tsfile usingprovideRouter(). - Update the
Appcomponent template (src/app/app.html) to use the<router-outlet />component to render routed content.
Reminder
You define routes as an array of route objects like this:
import { Routes } from '@angular/router'; export const routes: Routes = [ { path: 'page-one', component: PageOne }, { path: 'page-two', component: PageTwo }, ];Then, you provide a route configuration for your application in
app.config.tsby callingprovideRouter()(also imported from@angular/router)and passing your routes as a parameter.Checkpoint
Great, you now have routes and can technically navigate to them in the browser, but the app will still only display the Catalog page.
Feel free to verify this:
- Open the Web Browser tab,
- Navigate to the Catalog (
[baseUrl]/catalog) and Cart ([baseUrl]/cart) pages - Notice that the URL changes, but the app still shows the Catalog page every time
This is because the
Appcomponent is hard coded to render the Catalog component.Update the
Appcomponent's template (src/app/app.html) to render the<router-outlet />component instead. This ensures theAppcomponent always displays the content that corresponds to the current route/URL.Final Check for Step 2
Great! You can now navigate to the Catalog and Cart pages. Check it out:
- Open the Web Browser tab, or at {{localhost:4200}}
- Navigate to the Catalog (
[baseUrl]/cart) and Cart ([baseUrl]/cart) pages - Confirm that the URL changes and the correct page content is rendered for each route
- Define routes for the Catalog and Cart pages in a new
-
Challenge
Create a New Component with Navigation
You can now navigate to the
CatalogandCartpages by changing the URL, but you can't yet navigate to them by clicking on links.You could add links directly to the
Appcomponent, but instead add a newSiteHeadercomponent to get some practice creating new components. You'll add links to this new component in a later step.Use the Angular CLI to generate a new component named
SiteHeader.info> Reminder: You can generate new components with the CLI using the command:
ng generate component [ComponentName]or the abbreviated command:ng g c [ComponentName]warning> Important: Because of the unique lab environment you're working in, you must prefix Angular CLI commands with
ngcommands withnpx. For example:npx ng generate component [ComponentName]Great! You've created theSiteHeadercomponent, now make it so that theSiteHeadercomponent shows above every routed page.Remember, routed pages are rendered inside the
<router-outlet/>component you added to theAppcomponent template (src/app/app.html).If you want the content to render above every routed page, you can just add it to the
Appcomponent's template above the<router-outlet />. Nice! You should now see a Joe's Robot Shop Logo at the top left of every page in the Web Browser.It's a little big though and you're going to be adding more items to the
SiteHeaderthat need to be laid out correctly, so now is a good time to add some CSS styles to yourSiteHeadercomponent stylesheet. Now that your site header is rendering and styled, add navigation links for the Catalog and Cart pages. These links should appear after the logo.To add a link to an Angular route, use an anchor tag (
<a>) and use therouterLinkdirective to specify the path.For example, the following would navigate to the
page1route:<a routerLink="/page1">Page One</a>info> Remember: To use the
routerLinkdirective, you need to be sure to import theRouterLinkdirective in yourSiteHeadercomponent'simportsarray. -
Challenge
Pass Data to Child Components with Inputs
The
Catalogpage is currently displaying only a single product, and the data for that product is hard-coded.Take a look at the
product-detailscomponent class:src/app/product-details/product-details.tsNotice that it has a
productproperty, and that property is initialized in the constructor to a hard-coded "Friendly Bot" product. This means thisProductDetailscomponent can't be reused to render different products.A better approach is to make the
ProductDetailscomponent receive the product to display as an input property. Since the component cannot function without a product, this input should be required. Use a signal-based required input property for this.info> Remember: You can create a required signal-based input property using the following syntax:
myProperty = input.required<IMyPropertyType>();Because you changed theproductproperty on theProductDetailscomponent from a standard object to a signal-based input property, you need to update theProductDetailstemplate.Signal values are accessed like function calls, so anywhere the template references the product fields, update them to use
product(), for example:product().name. YourProductDetailscomponent can now receive aproductas an input. In fact it is required. Because of this, the Catalog page will no longer render.If you open the app in the Web Browser in a separate tab using {{localhost:4200}}), you can then open the Chrome DevTools and see that you're getting an error that says something like:
"Input "product" is required but no value is available yet."
This is because the Catalog component is not yet passing a value into the now-required
productinput on theProductDetailscomponent.Currently, the
Catalogcomponent renders a singleProductDetailscomponent. Later, you'll fetch product data from an API and use a loop to render multiple products. For now, to get your app rendering again and demonstrate passing data into the new input, update theCatalogcomponent to pass a hard-coded product object into theProductDetailscomponent.
How to Pass Data to an Input Property
You pass data to an input property using an input property attribute binding on the child component.
For example, to pass the value in
myObjectto themyPropertyinput property on a child component, you do something like this in the parent component:<my-child-component [myProperty]="myObject" /> -
Challenge
Create and Use Services for State Management
Currently, our
Catalogcomponent is only displaying a single product. In this step, you'll update theCatalogcomponent to fetch a list of products from the existingProductsService.Open
src/app/products-service.ts. Notice this service uses anHttpResourceto fetch an array of products from the API at/api/products. This project is using Angular's In-memory Web API to serve up an API without running a separate API server.You can see the array of products that is being returned from
/api/productsin the filein-memory-products.service.ts. Notice that this is an array of product objects which each have properties such asid,name, and others. When theProductsServicemakes an HTTP call to/api/products, this is the data that will be returned.The service also exposes a
productscomputed signal property. This signal contains the array of products returned from the API.Update the
Catalogcomponent class so that it:- Injects the
ProductsService - Uses a
@forloop in theCatalogcomponent's template to loop over the array of products from theproductproperty of the injectedProductsService
Reminder: Injecting a Service
To inject a service use the inject function.
For example:
protected myService = inject(MyService)
Reminder: Using
@forIn a TemplateYou use a
@forloop in a component template to loop over an array and render elements for each item in the array.The basic syntax for a
@forloop looks like this:@for (item of itemsArray; track item.id) { <my-child-component [itemProperty]="item" /> } ``` You’ve now practiced using an existing service, so next you’ll create your own. In this step, you’ll build a `CartService` to store and manage the items in the user’s cart. You’ll create the service using the Angular CLI, then add: - A signal-based `cart` property that stores an array of `IProduct` objects - A method to add items to the cart - A method to remove items from the cart --- ### Reminders - Create a service with: `npx ng generate service CartService` - Create a signal with a default value like: ```ts myName = signal<string>('Jim') ``` - Access a signal’s value by calling it like a function: ```ts myName() ``` - New services generated with the CLI are automatically decorated with `@Injectable({ providedIn: 'root' })` The cart should contain the logic for adding and removing items to/from the cart. Add two methods, `addToCart()` and `removeFromCart()`, to handle these operations. **Remember:** When you want to update a signal's value based on it's previous value (for example, adding items to the existing array), use the signal's `update` method. Example: ```ts myArraySignal.update((a) => [...a, newItem])Now, inject and use your new service on the product-details component to add items to the cart from the catalog page and display those items on the cart page. Nice! You can now add items to your cart from the Catalog page, but you still can’t see those items on the Cart page.
The
Cartcomponent is used to display the Cart page and is currently using a hard-codedcartItemsproperty to show a single hard-coded product.Your next steps will wire the Cart page into your new
CartService:- Update the
Cartcomponent to get its array of cart items from your newCartServiceinstead of using the hard-codedcartItems. - Then, update the
CartItemcomponent, which has theRemovefrom cart button so that it removes the associated item from the cart via theCartServicewhen clicked.
What You Learned
Congratulations, you've finished this lab and now have a functioning Robot Shop!
Throughout this lab you:
- Added routing and custom routes for your pages
- Created a new component with navigation links for each of your pages
- Styled your new component
- Used a
@forloop to repeat elements on the catalog page - Created, injected, and used services to manage the state of your application
Keep Learning
Check out the Pluralsight Angular: Components and Templates course and its associated lab to keep learning!
- Injects the
About the author
Real skill practice before real-world application
Hands-on Labs are real environments created by industry experts to help you learn. These environments help you gain knowledge and experience, practice without compromising your system, test without risk, destroy without fear, and let you learn from your mistakes. Hands-on Labs: practice your skills before delivering in the real world.
Learn by doing
Engage hands-on with the tools and technologies you’re learning. You pick the skill, we provide the credentials and environment.
Follow your guide
All labs have detailed instructions and objectives, guiding you through the learning process and ensuring you understand every step.
Turn time into mastery
On average, you retain 75% more of your learning if you take time to practice. Hands-on labs set you up for success to make those skills stick.