ng-components

Angular Components


Motivation

  • Code -> Funktionen -> Klassen -> Packages -> ...
  • 👍 Organisation, Maintainance, Testing, ...
  • UI -> 🤔

Component

  • Sichtbarer Teil des UIs (html, css)
  • Inklusive dazugehöriger Logik (typescript)


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

@Component({
  selector: 'app-some',
  templateUrl: './some.component.html',
  styleUrl: './some.component.css'
})
export class SomeComponent {
  // logic
}

Verwendung durch selector wie andere Tags

<!-- app.component.html -->
@for(_ of [1, 2, 3]; track $index) {
  <app-some></app-some>
}
app-some {
  border: 2px solid black;
}

Inline Templates

@Component({
  selector: 'app-toggle',
  template: `<button (click)='toggle()'>Toggle</button>`,
  styleUrls: ['./toggle.component.css']
})
export class ToggleComponent {
  // logic
}

Für kleine Components


View Encapsulation

  • css gilt nur für die Component die es definiert
  • /src/styles.css gilt global
  • weitere globale müssen in angular.json konfiguriert werden
"styles": [
  "node_modules/bootstrap/scss/bootstrap.scss",
  "node_modules/bootstrap-icons/font/bootstrap-icons.css",
  "src/styles.scss"
]

:host

:host {
  display: block;
  background: dodgerblue;
  border: 2px solid black;
}
  • Selected das host-Element der Component
  • display: inline default, selten sinnvoll

Struktur

Wie unterteilen?



Problem

Results und Basket brauchen die products

Wo speichern?


input()

Parent -> Child


input()

<!-- app.component.html -->
<app-results [products]='results()' >
@Component({...})
export class ResultsComponent {
  products  = input<Product[]>(); // read-only
  products2 = input<Product[]>([]); // default value
  products3 = input.required<Product[]>(); // required input   
}

model()

class BasketComponent {
  basket = model<Product[]>(); // ModelSignal, writeable

  clear() {
    this.basket.set([]);
  }
}

Two-Way Data Binding

<!-- app.component.html -->
<app-basket [(basket)]='basket' >

Problem

Add to basket - Button 🤔


output()

Child -> Parent


output()

<!-- results.component.html -->
@for(product of products(); track product.id) {
  <app-item (addToBasket)='addToBasket($event)' [product]='product'/>
}
@Component({...})
class ItemComponent {
  product = input.required<Product>();
  addToBasket = output<Product>()

  onButtonClicked() {
    this.addToBasket.emit(this.product());
  }
}
item.component.html    click 
item.component.ts      emit(product)
results.component.ts   addToBasket(product)

Lifecycle

@Component({...})
class SomeComponent implements OnChanges{
    
  ngOnChanges(changes: SimpleChanges) {
    // ...
  }
}