DEV Community

Cover image for Consuming APIs in Angular: Displaying Data In Components
Florimond Manca
Florimond Manca

Posted on • Updated on • Originally published at blog.florimond.dev

Consuming APIs in Angular: Displaying Data In Components

Welcome back! This article is a follow up to a previous article:

If you haven't read it yet — go check it out! This post will be referencing it quite often.

I recently had a question from @milankovach about how the CourseService could be used in a component, say, to display the list of courses.

Hi Florimond,
this is great but can you add short description (maybe here in comment section) how to use your services in other components for the n00bs? Thanks! :)

This is exactly what we'll cover in this beginner-friendly article.

This post should be helpful to anyone wondering how to retrieve and display data fetched from an external API. 😊

Quick refresher

In the original post, we discussed a design pattern that I use to standardise how my Angular apps communicate with REST APIs: the Model-Adapter pattern.

Given the GET /courses API endpoint, we built a Course model, a CourseAdapter and a CourseService that can help us fetch the list of courses from the API.

Here's what the project structure looks like for now:

src/app
├── app.component.css
├── app.component.html
├── app.component.ts
├── app.module.ts
└── core
    ├── course.model.ts
    └── course.service.ts
Enter fullscreen mode Exit fullscreen mode

The goal here is to build a CourseListComponent that fetches the list of courses using the CourseService, and displays them in the form of a simple unordered list.

Let's build!

Generating the CourseListComponent

Okay, let's get started. First, we will generate the component using the Angular CLI:

ng generate component CourseList
Enter fullscreen mode Exit fullscreen mode

The TypeScript (TS), HTML and CSS files for the component will be generated under src/app/course-list/. Here's what the TS file looks like so far:

// course-list/course-list.component.ts
import { Component, OnInit } from '@angular/core';

@Component({
  selector: 'app-course-list',
  templateUrl: './course-list.component.html',
  styleUrls: ['./course-list.component.css']
})
export class CourseListComponent implements OnInit {

  constructor() { }

  ngOnInit() {
  }

}
Enter fullscreen mode Exit fullscreen mode

Setting up attributes and templates

As a first step, let's add an empty list of courses on the component:

  // course-list/course-list.component.ts
  import { Component, OnInit } from '@angular/core';

  @Component({
    selector: 'app-course-list',
    templateUrl: './course-list.component.html',
    styleUrls: ['./course-list.component.css']
  })
  export class CourseListComponent implements OnInit {

+   courses: Courses[];

-   constructor() { }
+   constructor() {
+     this.courses = [];
+   }

    ngOnInit() {
    }

}
Enter fullscreen mode Exit fullscreen mode

Next, let's set up the template. Nothing fancy here, we're just using an *ngFor to display each course in its own list item, as well as the DatePipe to format the date.

<!-- course-list/course-list.component.html -->
<ul>
  <li *ngFor="let course of courses">
    <p>
      {{ course.name }} • {{ course.code }} • Created
      {{ course.created | date }}
    </p>
  </li>
</ul>
Enter fullscreen mode Exit fullscreen mode

While we're at it, let's update the AppComponent's template to display the list of courses:

<!-- app.component.html -->
<h1>Courses</h1>

<app-course-list></app-course-list>
Enter fullscreen mode Exit fullscreen mode

Alright! Let's fire up the browser, and we should be greeted with the "Courses" title and… an empty list. Why? Well, we haven't fetched any course yet!

Implementing the API endpoint

Before we go and plug the CourseService in, remember that for now it refers to https://api.myapp.com/courses — and that API doesn't exist!

That said, it would be nice to test the CourseService against a live server, wouldn't it?

So, let's build a quick backend API for this exact purpose. I'll be using Python and Bocadillo (shameless plug here: I am the maintainer of Bocadillo!) to provide the GET /courses endpoint we need to have access to from the browser.

You don't need to know about Python nor understand the code below, but I'm displaying it here for those interested:

# app.py
# Install: `pip install bocadillo`
from bocadillo import App

app = App(
    enable_cors=True,
    cors_config={"allow_origins": ["*"], "allow_methods": ["*"]},
)

COURSES = [
    {
        "id": 1,
        "code": "adv-maths",
        "name": "Advanced Mathematics",
        "created": "2018-08-14T12:09:45",
    },
    {
        "id": 2,
        "code": "cs1",
        "name": "Computer Science I",
        "created": "2018-06-12T18:34:16",
    },
]

@app.route("/courses")
async def courses_list(req, res):
    res.media = COURSES

if __name__ == "__main__":
    app.run()
Enter fullscreen mode Exit fullscreen mode

As you can see, the GET /courses endpoint will just return a hardcoded list of courses.

We can fire the API up in a terminal using $ python app.py, and leave it running.

Integrating the API with the CourseService

As a last integration step, we need to update the URL which the CourseService uses to fetch the courses:

// core/course.service.ts
// ...

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

  private apiUrl = 'http://localhost:8000/courses';

  constructor(
    private http: HttpClient,
    private adapter: CourseAdapter,
  ) { }

  list(): Observable<Course[]> {
    return this.http.get(this.apiUrl).pipe(
      // Adapt each item in the raw data array
      map((data: any[]) => data.map(item => this.adapter.adapt(item))),
    );
  }
}
Enter fullscreen mode Exit fullscreen mode

Fetching courses with the CourseService

We're now ready to plug the CourseService into the CourseListComponent!

Here are the steps we'll take to do it:

  1. Import the service.
  2. Inject it in the component using Angular's dependency injection.
  3. In the component's ngOnInit() method, get the RxJS observable to the list of course and subscribe to it.
  4. Store the fetched list of course on the component so that it gets rendered in the template.

Wondering how that translates into code? Take a look below — I added landmarks for each of the steps above:

import { Component, OnInit } from "@angular/core";
import { Course } from "../core/course.model";
// (1) Import
import { CourseService } from "../core/course.service";

@Component({
  selector: "app-course-list",
  templateUrl: "./course-list.component.html",
  styleUrls: ["./course-list.component.css"]
})
export class CourseListComponent implements OnInit {
  courses: Course[];

  // (2) Inject
  constructor(private courseService: CourseService) {
    this.courses = [];
  }

  ngOnInit() {
    // (3) Subscribe
    this.courseService.list().subscribe((courses: Course[]) => {
      // (4) Store
      this.courses = courses;
    });
  }
}
Enter fullscreen mode Exit fullscreen mode

Celebrate

There you go! If we open the browser at http://localhost:8000, we see the list of courses displayed in sexy Times New Roman.


Styling is, indeed, out of the scope of this blog post.

Wrapping up

Alright, let's see what we've achieved here:

  1. We generated the CourseListComponent using Angular CLI.
  2. We set up the component's courses attribute and its [template].
  3. We used Python and Bocadillo to build the API endpoint to test our component against.
  4. We used the CourseService and RxJS to fetch the list of course.

In fact, this is quite a typical workflow for me when I build web apps using Angular — I start by stubbing out the components, then implement the backend endpoints I need, and integrate them with the services to finally display the data.

If you're interested in the code, I uploaded it to a GitHub repo: ng-courses.

Stay in touch!

If you enjoyed this post, you can find me on Twitter for updates, announcements and news. 🐤

Top comments (6)

Collapse
 
gaurangdhorda profile image
GaurangDhorda

How to unsubscribe services in component after component destroy?

like this line of code " this.courseService.list().subscribe((courses: Course[]) "

how to unsubscribe ? Without unsubscribing Can we lead to memoryLeak of data overload?..

Collapse
 
florimondmanca profile image
Florimond Manca • Edited

Hi! This subscription won’t lead to memory leaks because it completes after the request finishes, i.e. the observable is bounded.

I’ve found this article useful to know when and how to unsubscribe from observables: netbasal.com/when-to-unsubscribe-i...

Collapse
 
gaurangdhorda profile image
GaurangDhorda

Thank you so much for this information!. helps to clear doubts on unsubscribing cases in one document shred by you. :)

Collapse
 
agarwalakash profile image
Akash Agarwal

Won't any Observable be returned from the service to the component? As there wasn't any request being made in the service.

Collapse
 
florimondmanca profile image
Florimond Manca

Hey! Thanks for chiming in. The code is available in the original article, so I cropped it for brevity, but I just added the part that defines the list() method. :-)

Collapse
 
agarwalakash profile image
Akash Agarwal

Yeah I was wondering the same! I liked the way you described everything in detail. :)