#angular #components #signals #binding

Day 2 β€” Mastering Angular Components, Templates & Data Binding

πŸ“˜ Day 2 β€” Mastering Angular Components, Templates & Data Binding

Hands-on Angular tutorial β€” Part of the Zero to Hero Series

Welcome to Day 2, where we dig into the heart of Angular:

  • βœ”οΈ Components
  • βœ”οΈ Templates
  • βœ”οΈ Data binding
  • βœ”οΈ Events
  • βœ”οΈ Inputs & outputs
  • βœ”οΈ Signals in components

Today, you’ll understand how Angular actually builds UI, and you’ll build three interactive components to practice.

Ready? Let’s code! πŸš€


🟦 What You Will Build Today

By the end of this tutorial, you’ll build:

  1. 1️⃣ A ProfileCard component
  2. 2️⃣ A Counter component (with signals)
  3. 3️⃣ A Two-way binding demo
  4. 4️⃣ Parent ↔ Child communication

All in real Angular code, no theory-only fluff.


🟧 1. What is a Component?

A component is basically:

  • HTML template
  • TypeScript logic
  • Styling
  • Metadata (@Component decorator)

In modern Angular (15+), ALL new components should be standalone:

  • βœ”οΈ No NgModules
  • βœ”οΈ Cleaner structure
  • βœ”οΈ Faster builds
  • βœ”οΈ Better routing
  • βœ”οΈ Angular 20 best practice

Let’s create one!


🟩 2. Creating Your First Standalone Component

Run:

ng generate component profile-card --standalone

Angular creates:

  • profile-card.component.ts
  • profile-card.component.html
  • profile-card.component.scss

By default, Angular does NOT auto-import your component into AppComponent. (Standalone components = no module to declare them in!)

We will do that next.


🟨 3. Understanding Component Anatomy

Open profile-card.component.ts. You should see something like:

import { Component } from '@angular/core';

@Component({
  selector: 'app-profile-card',
  standalone: true,
  templateUrl: './profile-card.component.html',
  styleUrl: './profile-card.component.scss'
})
export class ProfileCardComponent {}

Breakdown:

SectionMeaning
selectorHTML tag to use the component
standaloneTells Angular this component has no module
templateUrlHTML file
styleUrlSCSS/CSS file

Now let’s add content.


🟫 4. Building the ProfileCard Component

Open: profile-card.component.html

Replace with:

<div class="card">
  <img src="https://i.pravatar.cc/150?img=3" alt="Avatar" />
  <h2>{{ name }}</h2>
  <p>{{ role }}</p>
</div>

Now update the TS logic:

import { Component } from '@angular/core';

@Component({
  selector: 'app-profile-card',
  standalone: true,
  templateUrl: './profile-card.component.html',
  styleUrl: './profile-card.component.scss'
})
export class ProfileCardComponent {
  name = 'Sarah Connor';
  role = 'Angular Developer';
}

Add some simple CSS:

.card {
  width: 220px;
  padding: 16px;
  border-radius: 10px;
  background: #ffffff;
  box-shadow: 0 4px 18px rgba(0, 0, 0, 0.1);
  text-align: center;
}
img {
  border-radius: 50%;
  margin-bottom: 12px;
}

🟦 5. Display the Component in AppComponent

Open: app.component.ts

Add the component to imports:

import { Component } from '@angular/core';
import { ProfileCardComponent } from './profile-card/profile-card.component';

@Component({
  selector: 'app-root',
  standalone: true,
  imports: [ProfileCardComponent],
  templateUrl: './app.component.html',
  styleUrls: ['./app.component.scss'],
})
export class AppComponent {}

Now use the component in the template:

app.component.html:

<h1>Day 2: Components & Data Binding</h1>

<app-profile-card></app-profile-card>

Refresh β†’ You should see a beautiful profile card βœ”οΈ


🟩 6. Data Binding (Core of Angular Templates)

Angular supports 4 primary data-binding types:

  1. Interpolation (one-way: TS β†’ HTML)

    {{ username }}
  2. Property Binding

    <img [src]="imageUrl" />
  3. Event Binding

    <button (click)="doSomething()">Click</button>
  4. Two-way Binding

    <input [(ngModel)]="username" />

Let’s practice them all.


πŸŸ₯ 7. Build a Counter Component (Signals Version)

Generate:

ng generate component counter --standalone

Replace content:

counter.component.ts

import { Component, signal } from '@angular/core';

@Component({
  selector: 'app-counter',
  standalone: true,
  templateUrl: './counter.component.html'
})
export class CounterComponent {
  count = signal(0);

  increment() {
    this.count.update(c => c + 1);
  }

  decrement() {
    this.count.update(c => c - 1);
  }
}

counter.component.html

<h3>Counter: {{ count() }}</h3>

<button (click)="decrement()">-</button>
<button (click)="increment()">+</button>

Now import the component:

app.component.ts:

imports: [ProfileCardComponent, CounterComponent]

Use it:

app.component.html:

<app-profile-card></app-profile-card>
<app-counter></app-counter>

Now you have two working components!


🟦 8. Two-way Binding Demo (Inputs + Text)

Generate:

ng generate component message-editor --standalone

message-editor.component.ts

import { Component, signal } from '@angular/core';
import { FormsModule } from '@angular/forms';

@Component({
  selector: 'app-message-editor',
  standalone: true,
  imports: [FormsModule],
  templateUrl: './message-editor.component.html'
})
export class MessageEditorComponent {
  message = signal('Hello Angular!');
}

message-editor.component.html

<input [(ngModel)]="message()" />

<p>You typed: {{ message() }}</p>

Import it and use it:

app.component.ts:

imports: [ProfileCardComponent, CounterComponent, MessageEditorComponent]

Template:

<app-message-editor></app-message-editor>

🟩 9. Parent β†’ Child Communication (Inputs)

Update ProfileCard to accept data:

profile-card.component.ts

import { Component, input } from '@angular/core';

@Component({
  selector: 'app-profile-card',
  standalone: true,
  templateUrl: './profile-card.component.html',
  styleUrl: './profile-card.component.scss'
})
export class ProfileCardComponent {
  name = input<string>('Default User');
  role = input<string>('Frontend Developer');
}

Use it:

<app-profile-card
  [name]="'Luke Skywalker'"
  [role]="'Jedi Master'"
></app-profile-card>

🟫 10. Child β†’ Parent Communication (Outputs)

Generate:

ng generate component emoji-picker --standalone

emoji-picker.component.ts

import { Component, output } from '@angular/core';

@Component({
  selector: 'app-emoji-picker',
  standalone: true,
  templateUrl: './emoji-picker.component.html'
})
export class EmojiPickerComponent {
  choose = output<string>();

  sendEmoji(emoji: string) {
    this.choose.emit(emoji);
  }
}

emoji-picker.component.html

<button (click)="sendEmoji('😁')">😁</button>
<button (click)="sendEmoji('πŸ€”')">πŸ€”</button>
<button (click)="sendEmoji('πŸ”₯')">πŸ”₯</button>

Use it in AppComponent:

app.component.ts (logic)

selectedEmoji = signal('πŸ™‚');

updateEmoji(e: string) {
  this.selectedEmoji.set(e);
}

app.component.html

<h2>Selected Emoji: {{ selectedEmoji() }}</h2>

<app-emoji-picker (choose)="updateEmoji($event)"></app-emoji-picker>

Boom βœ”οΈ Real parent β†’ child β†’ parent communication.


πŸŽ‰ End of Day 2 β€” What You Learned

Today was big. You learned:

  • βœ”οΈ Creating standalone components
  • βœ”οΈ Component structure
  • βœ”οΈ Template syntax
  • βœ”οΈ Signals inside components
  • βœ”οΈ Property binding
  • βœ”οΈ Event binding
  • βœ”οΈ Two-way binding
  • βœ”οΈ Input & Output communication
  • βœ”οΈ Passing data between components

This is 80% of Angular’s foundation. You’re doing amazing.


πŸ§ͺ Day 2 Challenge

Build a component called:

πŸ‘‰ user-status

Features:

  1. Accept username as input
  2. Accept online (boolean) as input
  3. Show:

    John Doe β€” Online 🟒 OR John Doe β€” Offline πŸ”΄

  4. Add a toggle button in AppComponent to flip status
  5. Use signals for state