How to Build a News App Using Angular and Strapi

Strapi - Jul 18 - - Dev Community

Introduction

Angular and Strapi CMS combine to offer powerful possibilities for building dynamic applications.

Together, these technologies enable the creation of scalable, secure, and maintainable applications that can seamlessly integrate content management system with sophisticated user interactions, opening up opportunities for developers and businesses alike.

In this article, we will learn how to integrate Strapi into Angular by building a News application.

Prerequisites

In order to follow along with this tutorial, you will need the following:

What is Angular?

Angular, is a frontend framework, mostly used for building single-page applications. It is built and managed by Google. Angular makes it easy for developers to create functional and interactive websites that are well-structured and easy to maintain.

What is Strapi?

Strapi is a powerful headless content management system that is used to create, edit, and manage various types of content. When we say headless, we mean that, through a powerful API, it can connect to any frontend framework of your choice. Strapi supports both REST APIs and GraphQl.

Why Angular And Strapi?

By integrating Angular's frontend prowess with Strapi's backend management functionalities, developers can create web applications that not only boast visually appealing interfaces but are also easy to maintain and scale efficiently.

What is CRUD?

Now Let's understand dynamic web application by building a CRUD application using Angular for the Frontend and Strapi for the backend.

CRUD stands for Create, Read, Update, and Delete. It represents the four basic operations that can be performed on data in most database systems or web applications:

  1. Create: This operation involves creating new records or entries in the database. In a web application context, it typically refers to adding new data to the system. For example, adding a new todo task.

  2. Read: Reading, or retrieving, refers to fetching existing data from the database and displaying it to the user. For example, displaying a list of todo tasks.

  3. Update: Updating involves modifying existing data in the database. This could mean changing the values of certain fields in a record or updating the entire record itself. For example,modifying the details of a todo task.

  4. Delete: Deleting involves removing existing data from the database. It permanently removes records or entries from the system.For example, deleting a user account, removing a todo task.

Setting Up Your Backend Development Environment

Strapi Setup

Let's create a new project folder that will contain our Strapi backend. The command below creates a folder strapi-backend.

mkdir strapi-backend
Enter fullscreen mode Exit fullscreen mode

Navigate to the current directory by running the command below:

cd strapi-backend
Enter fullscreen mode Exit fullscreen mode

Finally, create a new Strapi app by running the command below:

npm create strapi-app news-app --quickstart
Enter fullscreen mode Exit fullscreen mode

001-strapi-installation.png

This will create a new strapi project. The Strapi server will be started at localhost:1337, and the URL localhost:1337/admin will automatically be loaded in our browser by Strapi.

002-strapi login.png

Fill in your details and click on the "Let's start" button. Strapi will create your account, and the admin dashboard will be displayed on your browser.

Create Collection and Content Types

The News app will have four content types:

  1. title: This is the title of the news
  2. content: This is the content of the news
  3. author: This is the author of the news
  4. imageUrl: This is the image of the news

Click "Create-Type Builder" to create a new collection type. A modal will pop up. Type "News App" in the Display name input box.

003-create-collection-type.png

This "News App" will be the name of our collection type, and the news endpoints will be from there.

Click on the "Continue" button, a modal will appear.

This modal will be to select field for our "News App" collection. The fields in our NewsApp model will be a "Text" field. So choose the "Text" field on the next user interface that shows. Type in "title" and click the "Add another field" button.

004-create-content-types.png

Repeat this process for the content,author, and imageUrl fields.

After that, click the "Finish" button. The modal will disappear, and we will see the NewsApp content types displayed with the fields that we have added. On the top right, click "Save," this will persist our NewApp collections to Strapi.

005-content-types.png

Also, see that at the sidebar that a "NewsApp" is added there alongside the "Users."

Enable Public Access

Before we test our endpoints, let's make them accessible to the public.
From the left sidebar, click on Settings. Again, on the left panel under USERS & PERMISSIONS PLUGIN, click on Roles, then click on Public from the table on the right.

Scroll to the "Permissions" section and click the "Select all" checkbox. This selection will allow any user to perform CRUD operations on the news's collection. Next, scroll up and click the “Save” button as shown below.

006-enable-public-access.png

Next, Open your project folder on your Vscode and start the server using the following commands:

npm run develop
Enter fullscreen mode Exit fullscreen mode

Make sure your server is running

Let’s test our NewsApp endpoints via Postman.

Make sure you have Postman installed. You can download it from here. If you are new to postman, you can read this documentation

News Endpoints

We have the following news endpoints:

  • POST /api/news-apps : This endpoint will be used to create a new news article. When a user sends a POST request to this endpoint, adding the required data in the request body, a new news article is created and stored in the database.

  • GET /api/news-apps: This endpoint is used to get or fetch a list of news articles. When a user makes GET request to this endpoint, it fetches a list of news articles already stored in the database.

  • GET /api/news-apps/:id: This endpoint is used to get a news article by its ID. When a user makes a GET request to this endpoint, adding the particular news article ID in the URL parameter, it returns that particular news article.

  • PUT /api/news-apps/:id: This endpoint is used when a user wants to update an existing news article. When a user makes a PUT request to this endpoint adding the ID of the news article to be updated in the URL parameter and the updated data in the request body, it modifies the news article accordingly in the database.

  • DELETE /api/news-apps/:id: This endpoint is used when a user wants to delete a news article. When a user makes a DELETE request to this endpoint with the ID of the news article to be deleted in the URL parameter, it removes the news article accordingly from the database.

Testing Endpoints Using Postman

Follow these steps to test the Strapi API on Postman
Open Postman and Create a Collection:
Open Postman, and make a new collection. Name it "News App."

Add a New Request - Create News:

  • Select the collection "News App."
  • Create a new request to add news data.
  • Use the endpoint: /api/news-apps.
  • Set the method to POST.
  • Go to the "Body" tab, select "raw".
  • Fill in the required fields and click "Send" to add new news data to Strapi.

007-create-news-with-postman.png

Get All News:

  • Test the endpoint to get all news data.
  • Use the endpoint: GET /api/news-apps.
  • Click "Send" to see all the news returned.

008-get-all-news-with-postman.png

See Data Fields:
Notice that Strapi adds fields like created_at, published_at, and updated_at to hold the creation, publication, and update dates respectively.

Get News By ID:

  • Retrieve news data by its ID.
  • Use the endpoint: GET /api/news-apps/{id}.
  • Enter the ID in the input box and press "Send."

009-get-news-by-id-with-postman.png

Edit News:

  • Edit news data using the PUT method.
  • Use the endpoint: /api/news-apps/{id}.
  • Edit the name of the news and click "Send" to save changes.

010-edit-new-with-postman.png

Delete News:

  • Delete news data using the DELETE method.
    • Use the endpoint: /api/news-apps/{id}.
    • Confirm deletion and ensure it's successful by doing a GET request to check if the item was deleted.

011-delete-news-with-postman.png

Setting up your Frontend Development Environment

For your convenience, the complete code and starter files for this project is on GitHub:
https://github.com/Okeke12nancy/starter-file.

There you will find two branches, the main and finished-project. The latter contains the complete code and the former contains the starter code.

Clone it and install the dependencies by typing the following command on your terminal.

npm install
Enter fullscreen mode Exit fullscreen mode

In this starter folder, inside the src/app folder we will see 4 components created for you.

  • create-news-app
  • modal
  • news-details
  • news-list

There is also a news.ts file that inside the models folder, and a news-servie.service.ts file inside the app folder.We will explain what each file is responsible for as we go on.

Create News

This component handles the creation of news articles, providing a form for input and functionality to submit the data.

In the create-news-app.component.html, paste the following code:

<form class="form_wrapper" (ngSubmit)="onSubmit()">
  <div class="label_input">
    <input
      type="text"
      name="title"
      id="title"
      [(ngModel)]="newArticle.title"
      required
      placeholder="Title"
    />
  </div>
  <div class="label_input">
    <textarea
      name="content"
      id="content"
      rows="3"
      [(ngModel)]="newArticle.content"
      required
      placeholder="Content"
    ></textarea>
  </div>
  <div class="label_input">
    <input
      type="text"
      name="author"
      id="author"
      [(ngModel)]="newArticle.author"
      required
      placeholder="Author"
    />
  </div>
  <div class="label_input">
    <input
      type="text"
      name="articleImage"
      id="articleImage"
      [(ngModel)]="newArticle.imageUrl"
      placeholder="Image Url"
    />
  </div>

  @if(!isLoading) {
  <button type="submit" class="createNews_btn">Create News</button>
  }@else {
  <button type="submit" disabled class="isLoading">Loading...</button>
  }
</form>

Enter fullscreen mode Exit fullscreen mode

This HTML code above defines a form for creating a new news article. Users can enter the title, content, author, and image URL. When they click the "Create News" button, the onSubmit function in the component class is triggered to handle form submission. The form uses data binding to keep the user input synchronized with the component's data. A button with text "Loading..." is displayed while data is submitted to prevent multiple submissions.

In the create-news-app.component.ts, paste the following code:

import { Component, EventEmitter, Input, Output } from '@angular/core';
import { NewsArticle } from '../models/news';
import { NewsServiceTsService } from '../news-service.ts.service';
import { FormsModule } from '@angular/forms';
import { CommonModule } from '@angular/common';
import { RouterModule } from '@angular/router';
import { ToastrService } from 'ngx-toastr';

@Component({
  selector: 'app-create-news-app',
  standalone: true,
  imports: [FormsModule, CommonModule, RouterModule],
  templateUrl: './create-news-app.component.html',
  styleUrl: './create-news-app.component.css',
})
export class CreateNewsAppComponent {
  @Output() isModalClose = new EventEmitter <boolean>()
  newsArticles: any = [];
  isLoading: boolean = false;

  newArticle: any = {
    title: '',
    content: '',
    author: '',
    imageUrl: '',
  };


  constructor(
    private newsService: NewsServiceTsService,
    private toastr: ToastrService
  ) {
  }

  ngOnInit() {
  }

  isEmpty(value: string | null): boolean {
    return value === '' || value === null;
  }

  onSubmit() {
    if (
      this.isEmpty(this.newArticle.title) ||
      this.isEmpty(this.newArticle.content) ||
      this.isEmpty(this.newArticle.author) ||
      this.isEmpty(this.newArticle.imageUrl)
    ) {
      this.toastr.warning(
        'Please fill in all required fields: Title, Content, and Author.'
      );
      return; 
    } else {
      console.log(this.newArticle);
      const article: any = {
        title: this.newArticle.title,
        content: this.newArticle.content,
        author: this.newArticle.author,
        imageUrl: this.newArticle.imageUrl,
      };
      this.isLoading = true;
      this.newsArticles.push(article);
      this.newsService.createNews({data : article}).subscribe(() => {
        this.newArticle.title = '';
        this.newArticle.content = '';
        this.newArticle.author = '';
        this.newsArticles.imageUrl = '';
        this.isLoading = false;
        this.closeModal()
      });
      this.toastr.success('Article Created');
    }
  }

  closeModal() {
    this.isModalClose.emit(false)
  }
}
Enter fullscreen mode Exit fullscreen mode

This Angular component manages creating news articles. It takes user input for title, content, author, and image URL, validates that all required fields are filled, uses a news service to send the new article data to the server, shows success/warning messages using a toast service, resets the form and closes a modal after successful creation.

012-create-news-form.png

Create Notification Modal

This component creates a modal dialog for displaying notifications to the user. It includes the structure and behavior for the modal.

In the modal.component.html, add the following code snippet;

<div *ngIf="isOpen" class="modal-wrapper" (click)="onClose()">
  <div class="mode" (click)="onModalClick($event)">
    <ng-content></ng-content>
  </div>
</div>
Enter fullscreen mode Exit fullscreen mode

This code controls a popup window (modal). It only shows the modal when a flag (isOpen) is true. Clicking outside the modal (on the wrapper) closes it.

In the modal.component.css, add the following code:

import { CommonModule } from '@angular/common';
import { Component, EventEmitter, Input, Output } from '@angular/core';

@Component({
  selector: 'app-modal',
  standalone: true,
  imports: [CommonModule],
  templateUrl: './modal.component.html',
  styleUrls: ['./modal.component.css']
})

export class ModalComponent {
  @Input() isOpen: boolean = false;
  @Input() modalType: string = '';
  @Output() isClose = new EventEmitter<boolean>()

  ngOnChanges(): void {
    this.toggleBodyOverflow(this.isOpen);
  }

  onClose(): void {
    this.isClose.emit();
  }

  onModalClick(event: Event): void {
    event.stopPropagation();
  }

  toggleBodyOverflow(open: boolean): void {
    const body = document.body;
    if (body) {
      body.style.overflow = open ? 'hidden' : 'unset';
    }
  }
}
Enter fullscreen mode Exit fullscreen mode

This code defines a reusable modal component in Angular. It takes inputs for isOpen (showing/hiding the modal) and modalType (potentially for different modal variations). It emits an isClose event when the modal is closed. It manages the body overflow (overflow: hidden) when the modal is open to prevent scrolling behind it.The onClose function triggers the isClose event to notify the parent component about closing. The onModalClick function prevents clicks within the modal from closing it.

Here is what the modal looks at the top-right corner of the image below.

013-notification-modal.png

Fetch and Display Data from Strapi Backend

The news-list component will be responsible for fetching data from the Strapi backend and displaying it on the frontend.

In the news-list.component.html, paste the following code:

<div class="wrapper">
  <div class="btn_wrapper">
    <button (click)="create()" class="createNews_btn">Create News</button>
  </div>
  <div class="display_news">
    @for (article of newsArticles; track article) {
    <div class="article_card">
      <img [src]="article.attributes.imageUrl" alt="" />
      <div class="article_details">
        <span class="article_title">{{ article.attributes.title }}</span>
        <span class="article_author">By {{ article.attributes.author }}</span>
        <button class="readMore_btn" (click)="onReadMore(article.id)">
          Read More
        </button>
      </div>
    </div>
    }
  </div>
  <app-modal [isOpen]="createModalOpen" (isClose)="createModalToggle(false)">
    <app-create-news-app (isModalClose)="closeFromCreate($event)"></app-create-news-app>
  </app-modal>
</div>

Enter fullscreen mode Exit fullscreen mode

This code displays a news list and a "Create News" button. Clicking the button opens a modal for creating new articles. News are listed in cards with title, author, image, and "Read More" button.
The modal opens based on a flag (createModalOpen) and closes the modal window when clicked outside or through the "Create News" component.

In the news-list.component.ts, paste the following code

import { Component } from '@angular/core';
import { FormsModule, ReactiveFormsModule } from '@angular/forms';
import { NewsArticle } from '../models/news';
import { ModalComponent } from '../modal/modal.component';
import { NewsServiceTsService } from '../news-service.ts.service';
import { Router, RouterLink } from '@angular/router';
import { CreateNewsAppComponent } from '../create-news-app/create-news-app.component';

@Component({
  selector: 'app-news-list',
  standalone: true,
  imports: [FormsModule, RouterLink, ModalComponent, CreateNewsAppComponent],
  templateUrl: './news-list.component.html',
  styleUrl: './news-list.component.css',
})
export class NewsListComponent {
  newsArticles: any = [];
  news!: any;
  createModalOpen: boolean = false;

  constructor(
    private newsService: NewsServiceTsService,
    private router: Router
  ) {

  }

  ngOnInit() {
    this.getNews();
  }

  onReadMore(id: any) {
    this.router.navigate(['/articles', id]);
  }

  create() {
    this.createModalOpen = true;
  }
  createModalToggle(open: boolean) {
    this.createModalOpen = open;
  }
  getNews() {
    this.newsService.getLocalState().subscribe((latestNews) => {
      this.newsArticles = latestNews.data;
    });
  }
  closeFromCreate(open: boolean) {
    this.createModalOpen = open;
  }
}

Enter fullscreen mode Exit fullscreen mode

This component manages a news list view. It fetches articles on startup and subscribes to updates from a news service. Clicking "Read More" on an article navigates to its detail page. The component integrates a modal window for creating new articles using separate components. It communicates with the create news component to handle modal opening/closing.

014-news-display.png

Show News Details

This component displays the details of a selected news article

In the news-detail.component.html

<div class="wrapper">
  <i class='material-icons back_icon' (click)="backToHomepage()">keyboard_backspace</i>
  <div class="inner_wrapper">
    <div>
      @if (!editModalOpen){
      <h2 class="article_title">{{ articleDetails.title }}</h2>

      } @else {
      <input
        class="article_title_input"
        type="text"
        [(ngModel)]="articleDetails.title"
      />
      }
    </div>
    <div >
      <img class="article_img" [src]="articleDetails.imageUrl" alt="" />
    </div>
    <!-- <div class="article_content"> -->
      @if (!editModalOpen){
      <div class="article_content">{{ articleDetails.content }}</div>

      } @else {
      <textarea
        class="article_content_input"
        [(ngModel)]="articleDetails.content"
        name=""
        id=""
        cols="30"
        rows="10"
      ></textarea>
      }
    <!-- </div> -->
    <div class="actions_btn">
      <i
        style="color: red; cursor: pointer"
        (click)="deleteConfirm()"
        class="material-icons"
        >delete</i
      >

      @if (!editModalOpen){<i
        style="color: blue; cursor: pointer"
        (click)="edit()"
        class="material-icons"
        >edit</i
      >} @else {<i
        style="color: green; cursor: pointer; width: 20px"
        (click)="editNews()"
        class="material-icons"
        >checkmark</i
      >}
    </div>
  </div>
  <app-modal [isOpen]="deleteModalOpen" (isClose)="deleteModalToggle(false)">
    <div class="modal_confirm">
      <h3>Are you sure you want to Delete Article?</h3>
      <div class="actions_modal">
        <button class="deleteBtn" (click)="deleteNews()">Delete</button>
        <button class="cancelBtn" (click)="cancel()">Cancel</button>
      </div>
    </div>
  </app-modal>
</div>

Enter fullscreen mode Exit fullscreen mode

This code displays an article detail view. It shows the article title and content, with an image. There's a "back" button and an "edit" button that toggles between displaying the content and editable input fields for title and content. Additionally, a "delete" icon triggers a confirmation modal asking for confirmation before deleting the article.

In the news-details.component.ts, paste the following code:

import { Component } from '@angular/core';
import { ActivatedRoute, Router } from '@angular/router';
import { NewsServiceTsService } from '../news-service.ts.service';
import { NewsListComponent } from '../news-list/news-list.component';
import { CreateNewsAppComponent } from '../create-news-app/create-news-app.component';
import { ModalComponent } from '../modal/modal.component';
import { FormsModule } from '@angular/forms';
import { ToastrService } from 'ngx-toastr';

@Component({
  selector: 'app-news-details',
  standalone: true,
  imports: [
    NewsListComponent,
    CreateNewsAppComponent,
    ModalComponent,
    FormsModule,
  ],
  templateUrl: './news-details.component.html',
  styleUrl: './news-details.component.css',
})
import { Component } from '@angular/core';
import { ActivatedRoute, Router } from '@angular/router';
import { NewsServiceTsService } from '../news-service.ts.service';
import { NewsListComponent } from '../news-list/news-list.component';
import { CreateNewsAppComponent } from '../create-news-app/create-news-app.component';
import { ModalComponent } from '../modal/modal.component';
import { FormsModule } from '@angular/forms';
import { ToastrService } from 'ngx-toastr';

@Component({
  selector: 'app-news-details',
  standalone: true,
  imports: [
    NewsListComponent,
    CreateNewsAppComponent,
    ModalComponent,
    FormsModule,
  ],
  templateUrl: './news-details.component.html',
  styleUrl: './news-details.component.css',
})
export class NewsDetailsComponent {
  newsArticles: any = [];
  deleteModalOpen: boolean = false;
  editModalOpen: boolean = false;
  articleId: any = '';
  articleDetails: any = {};

  constructor(
    private newsService: NewsServiceTsService,
    private router: Router,
    private route: ActivatedRoute,
    private toastr: ToastrService
  ) {}

  ngOnInit() {
    this.route.params.subscribe((params) => {
      const articleId = params['id'];
      this.newsService.getNewsById(articleId).subscribe((latestNews) => {
        this.articleDetails = latestNews.data.attributes;
        console.log(this.articleDetails.imageUrl);
      });
    });
  }

  deleteNews() {
    this.route.params.subscribe((params) => {
      const articleId = params['id'];
      this.newsService.deleteNews(articleId).subscribe(() => {
        this.newsArticles = this.newsArticles.filter(
          (news: any) => news.id !== articleId
        );
        this.router.navigate(['']);
        this.toastr.success('Article Deleted');
      });
    });
  }

  edit() {
    this.editModalOpen = true;
  }

  backToHomepage() {
    this.router.navigate(['']);
  }

  editNews() {
    this.route.params.subscribe((params) => {
      const articleId = params['id'];
      this.newsService.updateNews(articleId, {data:this.articleDetails}).subscribe(() => {
        this.editModalOpen = false;
        this.toastr.success('Article Updated ');
      });
    });
  }

  deleteModalToggle(open: boolean) {
    this.deleteModalOpen = open;
  }
  cancel() {
    this.deleteModalOpen = false;
  }
  deleteConfirm() {
    this.deleteModalOpen = true;
  }
}

Enter fullscreen mode Exit fullscreen mode

This component shows details for a single news article. It fetches the article by ID from the route parameters. Users can navigate back, edit the content, or delete the article. Editing updates the article and closes the edit modal. Deleting confirms with a modal before removing it from the list and navigating back.

015-news-details.png

Defining the News Model (news.ts)

This model represents the structure of a news item, providing type definitions for the properties of a news article.

On the news.ts, paste the following code:

export interface NewsArticle {
  id?: string;
  title: string;
  content: string;
  author: string;
  imageUrl: string;
  createdAt?: Date; 
  updatedAt?: Date; 
}

Enter fullscreen mode Exit fullscreen mode

This code defines an interface named NewsArticle. An interface is a blueprint that specifies the structure of an object in TypeScript.

Implementing the News Service (news-service.ts)

This TypeScript file defines a service that interacts with an external news API to fetch news data. It provides methods for retrieving news articles and managing news-related operations.

In the news-service.ts in the root folder, paste the following code:

import { Injectable } from '@angular/core';
import { HttpClient, HttpHeaders } from '@angular/common/http';
import { BehaviorSubject, Observable, timer } from 'rxjs';
import { NewsArticle } from '../app/models/news';
import { switchMap, tap } from 'rxjs/operators';

const httpOptions = {
  headers: new HttpHeaders({ 'Content-Type': 'application/json' }),
};

@Injectable({
  providedIn: 'root',
})
export class NewsServiceTsService {
 apiUrl = 'http://127.0.0.1:1337/api/news-apps';

  private newsSubject = new BehaviorSubject<any>([]);
  news$: Observable<any> = this.newsSubject.asObservable();

  constructor(private http: HttpClient) {
    this.getNews().subscribe(news => {
      this.newsSubject.next(news);
    });
  }

  createLocalState(news: any){
    return this.newsSubject.next(news)
  }

  getLocalState(): Observable<any> {
  return this.newsSubject.asObservable();
}

  createNews(news: any): Observable<NewsArticle> {
    return this.http.post<any>('http://127.0.0.1:1337/api/news-apps', news, httpOptions);
  }

  // this is the get news that works with the endpoint
  getNews(): Observable<any> {
    return timer(0, 5000).pipe(
      switchMap(() => this.http.get<any>('http://127.0.0.1:1337/api/news-apps' ))
    );
  }

// Get a specific news article by ID
  getNewsById(id: number): Observable<any> {
    const url = `${this.apiUrl}/${id}`;

    return this.http.get<any>(url);
  }

  // Update an existing news article
  updateNews(id:number, news: any): Observable<NewsArticle> {
    const url = `${this.apiUrl}/${id}`;
    return this.http.put<any>(url, news, httpOptions);
  }

  // Delete a news article by ID
  deleteNews(id: number): Observable<any> {
    // const url = `${this.apiUrl}/${id}`;
    console.log(id)
    return this.http.delete(`${this.apiUrl}/${id}`);
  }
}

Enter fullscreen mode Exit fullscreen mode
  • createNews: Takes a news object and sends an HTTP POST request to create a new news article in the server.
  • getNews: Makes an HTTP GET request to the API URL to retrieve all news articles.
  • getNewsById: Takes an ID and fetches a specific news article using an HTTP GET request with the ID appended to the API URL.
  • updateNews: Takes an ID and updated news data, then sends an HTTP PUT request to update the corresponding news article on the server.
  • deleteNews: Takes an ID and sends an HTTP DELETE request to remove the news article with that ID from the server.

Configuring Application Routes (app.route.ts)

This TypeScript file defines the routing configuration for the Angular application. It specifies the paths and corresponding components for different routes.

In the app.route.ts in the root folder, paste the following code:

import { NgModule } from '@angular/core';
import { RouterModule, Routes } from '@angular/router';
import { AppComponent } from './app.component';
import { NewsListComponent } from './news-list/news-list.component';
import { NewsDetailsComponent } from './news-details/news-details.component';

export const routes: Routes = [
  { path: '', component: NewsListComponent },
  { path: 'articles/:id', component: NewsDetailsComponent },
];

@NgModule({
  imports: [RouterModule.forRoot(routes)],
  exports: [RouterModule],
})
export class AppRoutingModule {}

Enter fullscreen mode Exit fullscreen mode

Users are directed to the NewsListComponent when they access the application root URL: "http://localhost:4200/".

The URL pattern articles/:id routes users to the NewsDetailsComponent. The :id part captures a parameter which corresponds to the ID of a specific news article. This allows routing to individual news articles based on their ID.

In the app.component.html located in the root folder of the project directory, paste the following code:

<router-outlet></router-outlet>
Enter fullscreen mode Exit fullscreen mode

The code above is a placeholder within your application's template where components load based on routing are inserted.

Setting Up the Main Component (app.component.ts)

This TypeScript file defines the main component of the Angular application. It serves as the root component, which is typically loaded when the application starts.

In the app.component.tslocated in the root folder of the project directory, paste the following code:

import { RouterLink, RouterLinkActive, RouterModule, RouterOutlet } from '@angular/router';
import { Component, OnInit } from '@angular/core';
import { NewsServiceTsService } from './news-service.ts.service';
import { NewsArticle } from './models/news';
import { CreateNewsAppComponent } from './create-news-app/create-news-app.component';
import { NewsListComponent } from './news-list/news-list.component';
import { CommonModule } from '@angular/common';
import { HttpClientModule } from '@angular/common/http';
import { AppRoutingModule } from './app.routes';
import { NewsDetailsComponent } from './news-details/news-details.component';

@Component({
  selector: 'app-root',
  standalone: true,
  imports: [CommonModule, RouterOutlet, CreateNewsAppComponent, NewsListComponent, NewsDetailsComponent],
  templateUrl: './app.component.html',
  styleUrl: './app.component.css'
})
export class AppComponent implements OnInit{
  newsArticles: NewsArticle[] =[]
  error: any;

}
Enter fullscreen mode Exit fullscreen mode

Here, news articles has a property newsArticles to hold an array of news articles. error allows storing potential errors during data fetching.

Now, we have to run our app. Type the following command on the terminal. I hope the Strapi backend is still running, if not start it up.

Run The Complete Angular Application

Before you run your application, make sure you have installed Angular CLI globally. If you haven't done that, please type the command below on your Vscode terminal:

npm install -g @angular/cli@latest
Enter fullscreen mode Exit fullscreen mode

In addition, make sure you have installed the dependencies required for the project. If you haven't done that, type the command below:

npm install
Enter fullscreen mode Exit fullscreen mode

Finally, to run the Angular server, type the command below:

ng serve --open
Enter fullscreen mode Exit fullscreen mode

This will serve the Angular app at http://localhost:4200.

Testing our Application

This is what the final application will look like:
demo.gif

Conclusion

In this article, we learnt about Angular and Strapi and how to integrate the two technologies when building a dynamic and interactive website by creating a News Application.

Integrating Strapi CMS into Angular made managing data efficient and accessible in less time. We could develop the backend quickly and get our API endpoints following best practices, saving us from the stress of building from scratch and solving bug related issues.

. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .