Featured resource
2026 Tech Forecast
2026 Tech Forecast

Stay ahead of what’s next in tech with predictions from 1,500+ business leaders, insiders, and Pluralsight Authors.

Get these insights
  • Lab
    • Libraries: If you want this lab, consider one of these libraries.
    • Core Tech
Labs

Guided: Angular Components and Templates

Imagine your team has begun developing an e-commerce website that sells robot parts. The site is mostly functional, your team has stopped short of implementing some more advanced component features to solve some existing challenges. Your mission? To dive into the codebase and make strategic improvements to enhance the user experience—all while mastering essential concepts related to Angular component communication and templates. 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 communicating between components with input and output properties, passing template content to be rendered by child components using content projection, utilizing control flow variables within a @for loop, and conditionally rendering content with @if and @else control flow blocks, reinforcing topics related building Angular components in a practical, real-world scenario. By the end of the lab, you will have the practical experience working with and communicating between components to help you start building your own dynamic web applications! Your robot parts store awaits its transformation.

Lab platform
Lab Info
Level
Beginner
Last updated
Dec 11, 2025
Duration
45m

Contact sales

By clicking submit, you agree to our Privacy Policy and Terms of Use, and consent to receive marketing emails from Pluralsight.
Table of Contents
  1. Challenge

    Introduction

    In this Angular guided lab, you’ll work with the Joe’s Robot Shop application. It’s already functional, but you’ll notice it has a few quirks.

    To see its current state:

    1. Click the Run button in the Terminal tab in the bottom-right.
    2. Then click the Web Browser tab to the right, or open the app in a new browser tab using this link: {{localhost:4200}}.

    You’ll see Catalog and Cart pages where you can purchase items and view them in your cart.

    However, each product currently displays both Add and Remove buttons. The developers intended to use a single ProductDetails component that conditionally shows these buttons depending on whether the component is rendered in the Catalog or Cart page—but they didn’t finish implementing that logic.


    What You'll Work On:

    Your job in this lab will be to:

    • Solve the issue with the buttons using input properties and @if…@else blocks,
    • Explore child-to-parent communication using output properties and events by delegating the handling of the Buy and Remove button clicks to the parent components,
    • Experiment with solving this problem using Content Projection and slots instead of input and output properties, and,
    • Use @for loop control flow variables to apply alternating styles to the products

    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 solution folder has been provided for you.


    Before You Get Started

    If you haven't already, click the Run button in the Terminal tab, then continue to the next step.

  2. Challenge

    Creating and Using Input Properties

    The Catalog and Cart pages each use the ProductDetails component which currently displays both Add and Remove buttons on both pages.

    Update the ProductDetails component so that its parent component can tell it which "mode" to operate in (shop mode or cart mode).

    info> Reminder: You can create a signal-based input property with a default value on a component like this: myProperty = input('value');. You can import input from @angular/core. Nice work! Now use your new mode input property to show and hide the appropriate Buy or Remove button using @if...@else blocks, based on the passed in mode value. Now that you have defined a mode property that controls the Add and Remove buttons, update the Catalog and Cart components to pass the appropriate values.

    info> Remember: You pass values to input properties using attributes. This can be a binding, for example, <child-component [myProperty]="boundValue" />. Or, if just working with string values, you can just using a simple attribute value, for example, myProperty="value".

  3. Challenge

    Creating Output Properties

    Currently, the ProductDetails component handles what happens when the user clicks the Buy or Remove buttons. That approach works, but there are times when you want the parent component (such as Catalog or Cart) to control what happens when these actions occur.

    Create two output properties named addedToCart and removedFromCart on the ProductDetails component which each output an event when the respective Add and Remove buttons are clicked. That will set you up to handle these events on their parent components.

    Keep in Mind

    • You can define output properties like this:

      myEvent = output<MyType>();
      

      (output can be imported from @angular/core)

    • You emit events via the output properties like this:

      this.myEvent.emit();
      
    • And you pass data/objects along with the event by passing the data as an argument:

      this.myEvent.emit(myObject);
      ``` Great! You now have the `ProductDetails` component outputting events when the **Add** and **Remove** buttons are clicked.
      
      

    Next, you can start handling those events on the parent components!

  4. Challenge

    Binding to Output Property Events

    Your ProductDetails component no longer updates the CartService when the buttons are clicked to add or remove products from the cart.

    Instead, it now emits an event that parent components can listen to to handle those events themselves.

    Update the Catalog and Cart components to listen to your new addedToCart and removedFromCart events and call the CartService.addToCart() and CartService.removeFromCart() methods, respectively.

    info> Remember: You can bind a child-component's output event to a method in the parent component's class using an attribute binding like this: [myEvent]="handleMyEvent($event)" In this example, passing $event to the handleMyEvent method passes along any data emitted by the myEvent output property. Nice! You're now using the parent Catalog component to add items to the cart based on the event and event data emitted from the ProductDetails component.

    Now apply the same pattern in the Cart component to handle the removedFromCart output event.

  5. Challenge

    Using Content Projection

    Taking a Different Approach

    There's another way to handle the Add and Remove buttons in the ProductDetails component.

    Instead of passing in a flag that tells the component which buttons to render, you could pass the buttons themselves from the parent component. This makes ProductDetails more reusable and extensible because the parent component can define any button or set of buttons it wants to display. This approach uses content projection to achieve this.

    Content Projection

    Content projection is a mechanism that allows a parent component to pass and render its own markup inside a designated area of a child component’s template. The child component chooses where projected content will appear using an <ng-content /> element.

    For example, consider this template for a child component with the selector <my-child-component />:

    <h1>Click here:</h1>
    <ng-content />
    <div>For magic!</div>
    

    A parent component could render a button inside this child component, where the <ng-content /> tag is, with a template such as this:

    <my-child-component>
      <button>Click me!</button>
    </my-child-component>
    

    Notice that the content to be projected, or inserted, into the child component is rendered inside the opening and closing tags for the child component.

    So, in this case, the parent component's "Click me!" button will be rendered between the <h1> and <div> of the child component, since that's where the <ng-content /> tag is.


    Try It Out!

    Right now the ProductDetails component renders either a Buy or Remove button based on its mode input property.

    Instead of this approach, allow parent components to pass in the button to be rendered using content projection. ### Looking Good Excellent, you're now using content projection to allow the parent components to control what buttons are displayed on the ProductDetails component.

    Check it out in the browser!

  6. Challenge

    Using @for Loop Variables

    Using @for Loop Variables

    Angular's @for control flow syntax allows you to access helpful loop variables, such as the index of each item, whether the item’s index is odd or even, or if it is the first or last item.

    Use the $even @for loop variable to style even rows on the catalog page so that the rows have an alternating background style. If the current item index is even, apply a bg-gray class to the list item that gives it a gray background.

    Keep in Mind

    You can access @for loop variables by defining them in the @for loop like this:

    @for (item of items; track item.id; 
    let i = $index; let even = $even) {
    

    You can optionally apply a CSS class based on an expression like this:

    <li [class.bg-gray]="even">
    

    What You Learned

    Congratulations, you've finished this lab and now have an improved Robot Shop application!

    Throughout this lab you:

    • Created and used input properties to pass data to child components
    • Used @if...@else blocks to conditionally render content
    • Created and bound to output properties to handle events from child components
    • Used content projection to pass content to child components, making them more extensible
    • Used the @for loop $even variable to style alternating rows inside a repeating list of elements

    Keep Learning

    Now check out the Pluralsight Angular: Services and Dependency Injection course to learn lots of great, and in-depth information about how to use services and dependency injection in your Angular applications!

About the author

Jim Cooper is a software developer at Pluralsight. With more than 20 years of software development experience, he has gained a passion for Agile software development -- especially Lean.

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.

Get started with Pluralsight