Passing Data From API Between Components in Angular

When developing single-page applications, one of the most common patterns you encounter is cross-component communication. One specific case I recently had to deal with is this: the page has two components: One for displaying the search for and the other for showing the search result.

Here is how to application works:

As you can see, after the user enters the search term and clicks Search, the results are displayed as a list below the search box.

How to run the demo

If you want to start using the demo right away, here is how

Prepare the API

docker run -p 9090:9090 codingpuss/fake-cat-api

This will run the API and you can access it at http://localhost:9090.

Endpoints details are available here: https://github.com/datmt/Fake-Cat-API

Start the frontend app

Clone the frontend repository from here: https://github.com/datmt/Fake-Cat-Frontend

Then run npm install && npm start.

You can try the app at http://localhost:4200.

The angular app’s structure

The following is the sequence diagram of API calling and updating.

In terms of components’ structure, the app component is the parent of Search and List components:

You can also see that in the code:
<h1>Cat search app</h1>


<app-cat-search (catEmitter)="onCatArrive($event)"></app-cat-search>

<app-cat-list-result [cats]="cats">

</app-cat-list-result>

The application flow

From the sequence diagram above, you can infer the full cycle from searching to displaying results:

  1. User enters search term
  2. User hit search button
  3. In search component, CatService is called
  4. CatService sends http request to the API
  5. API returns the result
  6. When the API results arrive, the Search component emit an event with updated data
  7. App component listens to that event and update the list of cats
  8. Since cats is an input of the List component, list of cats in the List component is updated
  9. New list of cats is renderred on the browser

Let’s follow the flow in code:

This is the Search component where we have the search box

<input type="text" [(ngModel)]="query"  placeholder="search cat by name">

<button (click)="search()">Search</button>

When a user clicks on the search button, the search() function is called.

Here is the search function:

 
export class CatSearchComponent implements OnInit {

  query: string = '';
  constructor(private catService: CatService) { }

  @Output() catEmitter = new EventEmitter<Cat[]>();
  ngOnInit(): void {
  }

  search() {
    this.catService.findByName(this.query).subscribe(t => this.catEmitter.emit(t));
  }

}

As you can see, the search function call the findByName function in CatService to retrieve the results from API.

Details of findByName as follow:

export class CatService {

  private catUrl = 'http://localhost:9090/cats/';
  constructor(
    private http: HttpClient
  ) { }

  getAll() : Observable<Cat[]> {
    return this.http.get<Cat[]>(this.catUrl + 'list')
  }

  findByName(query: string): Observable<Cat[]> {
    return this.http.get<Cat[]>(this.catUrl + 'search/' + query)
  }
}

Go back to the search function in the search component, you can see that after the results from API arrives, the event catEmitter will emit the results. As mentioned above, the App component listens to this event and the handler is onCatArrive

<app-cat-search (catEmitter)="onCatArrive($event)"></app-cat-search>

What onCatArrive does is it updates the variable cats to the value of the data of catEmitter:

export class AppComponent {

  cats: Cat[] = [];
  title = 'fake-cat';

  onCatArrive($event: Cat[]) {
    this.cats = $event;
  }
}

Since the List components take cats as an input, the value of cats inside it will be updated accordingly:

app.component.html

<app-cat-list-result [cats]="cats">

cat-list-result.component.ts

export class CatListResultComponent implements OnInit {

  @Input() cats!: Cat[];
  constructor(
    private catService: CatService
  ) { }

  ngOnInit(): void {

  }

}

cat-list-results.component.html

<ul *ngIf="cats.length > 0; else noCat">
  <li *ngFor="let cat of cats">{{cat.name}}</li>
</ul>

<ng-template #noCat>
  <h3>No cat available</h3>
</ng-template>

Leave a Comment