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 theproperties
an article should contain - Refactor the
ArticleComponent
so it works together with theinterface
- Creating a
service
class
with amethod
that returns 2 dummy articles - Injecting the
service
in ourHomeComponent
, getting the 2 articles and using theArticleComponent
to show these 2 articles
- Creating an
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 thesrc/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 ourAPI
export
- Don't forget to
export
theinterface
, this way we can import (and use it) in otherTypeScript
classes (components
,services
,interfaces
,...)
Refactoring the ArticleComponent to work with the interface
- We want to be able use the
ArticleComponent
in any othercomponent
to show the article - An
article
is now defined by aninterface
- When calling the
ArticleComponent
we can pass anarticle
asinput
parameter, which will be used to construct the correctHTML
- 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 thearticle element
when thearticle property
in theArticleComponent
is not undefined
{{article.title}} <!-- interpolation -->
interpolation
: shows thetitle
-value of thearticle
Data-binding
- In the
ArticleComponent
we are making use ofdata-binding
. In essence this means that you can show the values of anyproperty
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 theproperty
we want to show e.g.article.title
for the title - This form of
data-binding
is calledinterpolation
@Input() decorator
- The
@Input()
decorator before theproperty
means that we can pass a value to it when calling thecomponent
- We'll see how it works when we show the
ArticleComponent
on theHomeComponent
Creating the service
- In Angular, a
service
is typically aclass
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 thesrc/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 forservice
article
: name of theservice
, 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;
}
}
code | description |
---|---|
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 theconstructor
. - 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 theArticleService
- 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>
}
code | description |
---|---|
<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 aproperty
(array of article) in thehome.component.ts
, therefore we can use it in our template (HTML
)article
is thecursor
from the*ngFor
directive (let article of articles
)
@Input() decorator (2)
- If we specify the
@Input()
decorator without aparameter
, the property that you can use in thetemplate
will be the name of theproperty
@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 ourhome.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:

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 apublishDate
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