📊 Progress Bar Demo (Day 7)

Upload Progress ({{ uploadProgress }}%)

Video Progress ({{ videoProgress }}%)

Download Progress ({{ downloadProgress }}%)

Test voi cac gia tri khac nhau:

👥 Component Interaction Demo (Day 8)

Demo Output va EventEmitter - Child component gui event len Parent component khi click nut Delete

🔄 Custom Two-way Binding Demo (Day 9)

Demo Two-way binding với Toggle component và ngModel

📝 ngModel Two-way Binding

Hello, {{ userName }}!

🎯 Custom Toggle Two-way Binding

Toggle 1

State: {{ toggleState1 ? 'ON' : 'OFF' }}

Toggle 2

State: {{ toggleState2 ? 'ON' : 'OFF' }}

Toggle 3

State: {{ toggleState3 ? 'ON' : 'OFF' }}

💡 Cách hoạt động:

1. Two-way binding syntax: [(checked)]="toggleState1"

2. Tương đương với: [checked]="toggleState1" (checkedChange)="toggleState1 = $event"

3. Component can: Input() checked va Output() checkedChange

4. Test: Click toggle hoặc button "Toggle from Parent" để xem sync

🎯 Content Projection Demo (Day 13)

Demo ng-content với các loại selector: attribute, class, tag, và ngProjectAs

1. Basic ng-content (Single Slot)

Do you like Angular?
Do you use TypeScript?
Do you want to learn more?

Code: <ng-content></ng-content> - Nhận tất cả content không có selector

2. Multi-slot ng-content (Multiple Selectors)

📝 Survey Card

Please answer the following questions about your Angular experience.

Your responses help us improve our content.

⭐ Results Card

Question 1: {{ surveyAnswers.question1 ? '✅ Yes' : '❌ No' }}

Question 2: {{ surveyAnswers.question2 ? '✅ Yes' : '❌ No' }}

Question 3: {{ surveyAnswers.question3 ? '✅ Yes' : '❌ No' }}

Selectors:
select="[slot=header]" - Attribute selector
select=".card-footer-content" - CSS Class selector
select=".card-actions" - Class selector cho actions
select="button" - Tag selector cho buttons
<ng-content> - Default slot (không có selector)

🐛 Debug Card - Simple Test:

Debug Header

This is body content

3. ngProjectAs Demo

Sử dụng ngProjectAs để project content vào đúng slot ngay cả khi element không match selector trực tiếp.

📊 Survey Details

Here are your current survey responses:

Do you like Angular? {{ surveyAnswers.question1 ? '✅ Yes' : '❌ No' }}
Do you use TypeScript? {{ surveyAnswers.question2 ? '✅ Yes' : '❌ No' }}
Do you want to learn more? {{ surveyAnswers.question3 ? '✅ Yes' : '❌ No' }}

Note: Elements trên sử dụng ngProjectAs="modal-header"ngProjectAs="modal-body" để project vào đúng slots.

💡 Content Projection Summary:

1. Single Slot: <ng-content></ng-content> - Nhận tất cả content

2. Attribute Selector: <ng-content select="[slot=header]">

3. Class Selector: <ng-content select=".card-footer-content">

4. Tag Selector: <ng-content select="button">

5. ngProjectAs: <div ngProjectAs="modal-header"> - Project vào slot cụ thể

6. Multiple ng-content: Mỗi selector sẽ nhận content phù hợp

🎨 Day 14: ng-template, ngTemplateOutlet & ng-container

Demo các khái niệm về template rendering và reusable templates

1. ng-template với *ngIf else (Review)

✅ Bạn có thể xem nội dung dành cho người lớn
❌ Bạn chưa đủ tuổi để xem nội dung này
ng-template chỉ render khi được gọi (ở đây là khi *ngIf else)

2. Reusable Template với ngTemplateOutlet

Header Section:
You have selected items.
Body Section:
There are items in your cart.
Footer Section:
Total selected: items.
{{ itemCounter }} 📦
✨ Template #counterTemplate được tái sử dụng 3 lần thay vì copy-paste code

3. ngTemplateOutlet với Context (truyền data)

Reusable Button Template:

Action Log:

{{ action.time }} - {{ action.message }}
No actions yet. Click a button above!
✨ Template nhận data qua ngTemplateOutletContext:
let-label="label" - bind context.label vào variable label
let-implicitLabel - bind context.$implicit vào variable implicitLabel
let-onClick="onClick" - truyền function callback

4. ng-container vs div (Demo DOM structure)

❌ Với div (tạo extra DOM):

Inspect element để thấy extra <div> bao quanh

✅ Với ng-container (clean DOM):

Inspect element - không có extra wrapper element
⚠️ ℹ️ {{ message }}
ng-container không tạo DOM element, giúp HTML clean hơn và tránh ảnh hưởng CSS

5. Template as Component Input (Advanced)

Truyền template từ parent component vào child component để customize giao diện

🎨 Default Card

This card uses the default styling and layout defined in the Card component.

🚀

Custom Styled Card

với template được customize

{{ data.title }}

{{ data.description }}

#{{ tag }}
⚡ Powered by ng-template {{ getCurrentTime() }}
✨ Templates có thể nhận data và được tái sử dụng với context khác nhau

💡 Day 14 Summary

ng-template

  • • Định nghĩa template không render trực tiếp
  • • Sử dụng với structural directives
  • • Tái sử dụng code HTML
  • • Có thể nhận data qua context
  • • Reference bằng #templateName

ngTemplateOutlet

  • • Render ng-template đã định nghĩa
  • • Cú pháp: [ngTemplateOutlet]="ref"
  • • Truyền data qua ngTemplateOutletContext
  • • Hỗ trợ $implicit cho default value
  • • Cho phép template reuse

ng-container

  • • Container không tạo DOM element
  • • Tránh wrapper element thừa
  • • Không ảnh hưởng CSS styling
  • • Sử dụng với structural directives
  • • Clean HTML output

🎯 Best Practices:

  • 1. Reusability: Dùng ng-template cho code HTML lặp lại trong component
  • 2. Clean DOM: Dùng ng-container thay vì div khi không cần wrapper element
  • 3. Type Safety: Cẩn thận với context data vì không có type checking
  • 4. Performance: Templates chỉ render khi được gọi, giúp optimize performance
  • 5. Flexibility: Cho phép parent component customize child component template

🔧 DI Demo (Day 15)

🛍️ Product List (với DI)

🛒 Cart View (Service Sharing)

🎯 DI Demo Summary

Constructor Injection: ProductService và CartService được inject vào components

Service Sharing: Cùng CartService instance được share giữa ProductList và CartView

Loose Coupling: Components không phụ thuộc vào concrete implementations

Testability: Dễ dàng mock services cho unit testing

Maintainability: Có thể thay đổi implementation mà không ảnh hưởng components