Skip to main content

How to show multiple articles using an interface, a service and component interaction

January 30, 2024About 4 min

How to show multiple articles using an interface, a service and component interaction

  • Our goal in this module is to show a list of articles on the homepage
  • We will take the following steps to achieve this:
    • Creating an interface for an article with all the properties an article should contain
    • Refactor the ArticleComponent so it works together with the interface
    • Creating a service class with a method that returns 2 dummy articles
    • Injecting the service in our HomeComponent, getting the 2 articles and using the ArticleComponent to show these 2 articles

What is an interface?

  • An interface is a specification that identifies a related set of properties and methods to be implemented by a class. In other words, a given class agrees to support this specification when it implements that interface.
  • The interface is simply the definition of the properties and methods, and the class that implements that interface has the actual code for each of those defined properties and methods. In Typescript, you can use the interface itself as a data type. Interfaces in Typescript are a development time only concept, they are not included in the final JavaScript after the build process.

Creating the interface

  • An article is a collection of properties which define the state of the article
  • Create a new article.ts file in the src/app folder:
export interface Article {
    id: number;
    title: string;
    subtitle: string;
    imageUrl: string;
    imageCaption: string;
    content: string;
    author: string;
    publishDate: string;
}
  • This interface will be used to create our 2 dummy articles
  • Later on we can re-use this interface if we get articles back from our API

export

  • Don't forget to export the interface, this way we can import (and use it) in other TypeScript classes (components, services, interfaces,...)

Refactoring the ArticleComponent to work with the interface

  • We want to be able use the ArticleComponent in any other component to show the article
  • An article is now defined by an interface
  • When calling the ArticleComponent we can pass an article as input parameter, which will be used to construct the correct HTML
  • Modify the article.component.ts file as follows:
import { Component, Input, OnInit } from '@angular/core';
import { Article } from '../article';

@Component({
  selector: 'app-article',
  standalone: true,
  imports: [],
  templateUrl: './article.component.html',
  styleUrls: ['./article.component.css']
})
export class ArticleComponent implements OnInit {
  @Input() article!: Article;

  constructor() { }

  ngOnInit(): void {
  }

}
 
 








 
 



 
 


  • Modify the article.component.html file as follows:
@if(article) {
<article>
    <h1>{{article.title}}</h1>
    <h4>{{article.subtitle}}</h4>
    <figure>
        <img src="{{article.imageUrl}}" alt="{{article.imageCaption}}">
        <figcaption>{{article.imageCaption}}</figcaption>
    </figure>
    <p>
        {{article.content}}
    </p>
    <footer>
        <p>Author: {{article.author}}, Published: {{article.publishDate}}</p>
    </footer>
</article>
}
  • @if(article) { ... }: only show the article element when the article property in the ArticleComponent is not undefined
{{article.title}} <!-- interpolation -->
  • interpolation: shows the title-value of the article

Data-binding

  • In the ArticleComponent we are making use of data-binding. In essence this means that you can show the values of any property defined in the class file (article.component.ts) on your template file (article.component.html)
  • We use the double curly brackets to access the property, and in this case the .xxx notation to navigate to the property we want to show e.g. article.title for the title
  • This form of data-binding is called interpolation

@Input() decorator

  • The @Input() decorator before the property means that we can pass a value to it when calling the component
  • We'll see how it works when we show the ArticleComponent on the HomeComponent

Creating the service

  • In Angular, a service is typically a class with a narrow, well-defined purpose.
  • In our app, an ArticleService which gives us a list of articles would be convenient
  • Create the ArticleService in the src/app folder by executing the following command:
ng g s article
  • This results in the article.service.ts file

ng g s article

  • s : shorthand notation for service
  • article : name of the service, name will be suffixed with .service
  • Replace the content of the article.service.ts file with the following code:
import { Injectable } from '@angular/core';
import { Article } from './article';

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

  constructor() { }

  getArticles(): Article[] {
    let articles: Article[] = [];

    let article1: Article = {
      id: 1,
      title: "Title article",
      subtitle: "Subtitle article",
      imageUrl: "https://images.pexels.com/photos/1202723/pexels-photo-1202723.jpeg?auto=compress&cs=tinysrgb&dpr=2&h=100&w=134",
      imageCaption: "caption image",
      content: `Lorem ipsum dolor sit amet consectetur adipisicing elit. Tenetur voluptas sequi voluptatum pariatur! Quae cumque
      quidem dolor maxime enim debitis omnis nemo facilis sequi autem? Quae tenetur, repellat vero deleniti vitae
      dolores? Cum tempore, mollitia provident placeat fugit earum, sint, quae iusto optio ea officiis consectetur sit
      necessitatibus itaque explicabo?`,
      author: "Michaƫl Cloots",
      publishDate: "28/11/2020"
    };

    let article2: Article = {
      id: 2,
      title: "Title article 2",
      subtitle: "Subtitle article 2",
      imageUrl: "https://images.pexels.com/photos/3422964/pexels-photo-3422964.jpeg?auto=compress&cs=tinysrgb&dpr=2&h=100&w=134",
      imageCaption: "caption image 2",
      content: `2 Lorem ipsum dolor sit amet consectetur adipisicing elit. Tenetur voluptas sequi voluptatum pariatur! Quae cumque
      quidem dolor maxime enim debitis omnis nemo facilis sequi autem? Quae tenetur, repellat vero deleniti vitae
      dolores? Cum tempore, mollitia provident placeat fugit earum, sint, quae iusto optio ea officiis consectetur sit
      necessitatibus itaque explicabo?`,
      author: "Florian Smeyers",
      publishDate: "30/11/2020"
    };

    articles.push(article1);
    articles.push(article2);

    return articles;
  }

}

 








 
 

 
 
 
 
 
 
 
 
 
 
 
 
 






















codedescription
import { Article } from './article';We want to make use of the Article-interface, so we must import the file (this is just a JS import and has nothing to do with the modularity system in Angular)
getArticles(): Article[] { ... }Method which returns an Article-array with 2 dummy articles
let articles: Article[] = [];Declaration of the Article-array
let article1: Article = { ... }Notation for creating a variable based on the Article-interface

Calling the service in the HomeComponent

  • If you want to use a service in your component you have to inject it into the constructor.
  • For our home.component.ts:
import { Component } from '@angular/core';
import { Article } from '../article';
import { ArticleService } from '../article.service';
import { ArticleComponent } from '../article/article.component';

@Component({
  selector: 'app-home',
  standalone: true,
  imports: [ArticleComponent],
  templateUrl: './home.component.html',
  styleUrls: ['./home.component.css']
})
export class HomeComponent {
  articles: Article[] = [];

  constructor(private articleService: ArticleService) { }

  ngOnInit(): void {
    this.articles = this.articleService.getArticles();
  }
}

 
 
 




 






 


 


  • In the ngOnInit() lifecycle hook method we get all the articles via the ArticleService
  • This is a private variable which can be accessed through the this keyword (= context of class)
  • At last we can perform another data-binding (interpolation) to show the articles on the template (HTML):
<h1>Welcome home</h1>
@for (article of articles; track $index) {
    <app-article [article]="article"></app-article>
}
codedescription
<app-article></app-article>Selector for our ArticleComponent. This way the component will be loaded
@for (article of articles; track $index) { ... }structural directive: for each article in the array (what we get back from the ArticleService I want to load the ArticleComponent)
[article]="article"Passing the article as a parameter (which is the @Input() article property in the ArticleComponent

Data-binding

  • articles is a property (array of article) in the home.component.ts, therefore we can use it in our template (HTML)
  • article is the cursor from the *ngFor directive (let article of articles)

@Input() decorator (2)

  • If we specify the @Input() decorator without a parameter, the property that you can use in the template will be the name of the property
    • @Input() article: Article; : [article]="article"
  • We can specify a custom name by defining the parameter:
    • @Input("newsArticle") article: Article; : [newsArticle]="article"
  • Because we now use the ArticleComponent directly in our home.component.html (for loop!), we have to import it!
// home.component.ts
@Component({
  selector: 'app-home',
  standalone: true,
  imports: [ArticleComponent],
  templateUrl: './home.component.html',
  styleUrls: ['./home.component.css']
})
export class HomeComponent {




 




Result:

home
home

Exercise

Take a backup of the current state of your application (or create a new branch)

  • Create a new method in the ArticleService that only gets the articles with a publishDate that is within one week of today
  • Show a message "No articles found" when there are no articles to be displayed
  • Play around with the publish dates to test all use cases