Externe Daten laden

Externe Daten laden wir in Angular mit dem HttpClientModul. Für die Nutzung ist ein Import im App-Module notwendig.

@NgModule({
  declarations: [
    AppComponent,
    ListComponent,
    CreateComponent
  ],
  imports: [
    BrowserModule,
    HttpClientModule, // Kommunikation mit Backend über HTTP
    FormsModule // ermöglicht Template-Driven-Forms
  ],
  providers: [],
  bootstrap: [AppComponent]
})
export class AppModule {
}

API Aufruf in einer Komponente?

Und wo laden wir dann die Daten? Direkt in einer Komponente? Bitte nicht! Die API kann sich ändern und wir möchten deshalb nicht jede Komponente anpassen, welche Daten der API nutzt.

Wir laden die Daten in einem Service. Mithilfe der Dependenciy Injektion erhalten wir eine Instanz vom HttpClient, wenn wir diesen im Konstruktor angegeben haben. Durch die Nennung im Konstruktor weiß Angular, dass wir eine Instanz benötigen. Das Angular-Framework kümmert sich um die Erstellung und Verwaltung der Instanzen. Wir bekommen eine Instanz zurückgeliefert.

@Injectable({
  providedIn: 'root'
})
export class PostsService {
  constructor(private http: HttpClient) {
  }
}

Die Initialisierung des Services erfolgt mit {providedIn: 'root'} auf AppModule-Ebene. Deshalb können mehrere Komponenten innerhalb des AppModules auf die gleiche Instanz des Service zugreifen. Dadurch Arbeiten alle Komponenten auf demselben Datenstand.

Für die Datenhaltung in Angular erstellen wir eine Entität, die Daten in unserer Anwendung bereitstellt. Die Methode fromJson transformiert eine JavaScript-Objekt (kommend von einer API), in die gewünschte Entität um.

export class PostEntity {
  userId: number;
  id: number;
  title: string;
  body: string;

  static fromJson(obj: object): PostEntity {
    const newEntity = new PostEntity();

    if (obj.hasOwnProperty('userId')) {
      newEntity.userId = Number(obj['userId']);
    }

    if (obj.hasOwnProperty('id')) {
      newEntity.id = Number(obj['id']);
    }

    if (obj.hasOwnProperty('title')) {
      newEntity.title = obj['title'];
    }

    if (obj.hasOwnProperty('body')) {
      newEntity.body = obj['body'];
    }

    return newEntity;
  }
}

HTTP Zugriff

Der lesende API-Zugriff wird mit Get realisiert. Veränderung und Neuerzeugung nutzen Post und gelöscht mit Delete – zu mindestens in unser genutzten API. Das ist abhängig von der eingesetzten Schnittstelle. Nutze die Dokumentation deiner API. Hier findest du alle relevante Informationen.

Wir holen uns die Daten von Server und transformieren die Daten in unser gewünschtes Format.

Tipp: Für Performance-Optimierung kann es sinnvoll sein, die Inhalte zu Cachen oder nur bestimmte Inhalte herunterzuladen und bei Bedarf zu vervollständigen. Dafür kann die RxJS Operation shareReplay eingesetzt werden.

import {Injectable} from '@angular/core';
import {PostEntity} from './post.entity';
import {HttpClient} from '@angular/common/http';
import {map} from 'rxjs/operators';

@Injectable({
  providedIn: 'root'
})
export class PostsService {

  list: PostEntity[] = [];

  constructor(private http: HttpClient) {
    this.http.get('https://jsonplaceholder.typicode.com/posts').pipe(
      map((list: object[]) => list.map((e: object) => PostEntity.fromJson(e)))
    ).subscribe(
      (list: PostEntity[]) => this.list = list
    );

  }


  add(post: PostEntity) {
    this.http.post('https://jsonplaceholder.typicode.com/posts', post).pipe(
      map((e: object) => PostEntity.fromJson(e)),
    ).subscribe(
      (item: PostEntity) => this.list.unshift(item)
    );
  }

  delete(post: PostEntity) {
    this.http.delete('https://jsonplaceholder.typicode.com/posts/' + post.id).pipe(
    ).subscribe(
      () => {
        const index = this.list.indexOf(post);
        if (index !== -1) {
          this.list.splice(index, 1);
        }
      }
    );
  }

}

Für die Darstellung müssen wir dann nur noch die PostsService in einer Komponente einbauen. Mit einer for Schleife integrieren wir über eine Liste und zeigen jeden geladenen Eintrag an.

Der gesamte Programmcode ist unter https://github.com/dornsebastian/angular-crud zu finden.

Der nächste Teil beschäftigt sich mit Routen-basierten Datenladen mit Resolvern.