Angular & Headless CMS

Build a Blog with Angular and Contentful

I have built a blog application using Angular and a headless CMS, Contentful. Contentful gives developers and non-developers alike the ability to manage content in a web application. I use Contentful to manage content on my website. — I am not sponsored by Contentful and any headless CMS could be substituted. See alternatives [1]

Live Demo 🌌

Download the Source Code 🚀

App Overview

Summary

What is a Headless CMS

Contentful Basics

Angular: Accessing & Displaying Content

Hosting

What is a Headless CMS

As I learned to build web applications, I heard about Content Management Systems (CMS), such as Wordpress or Drupal. I thought to myself, why would a developer use this if they already know how to build a website? At the time, I did not understand the need or use-case.

Later, when I was ready to create my own side-projects and ship them to non-developers, I paused.

How can someone who is not a developer update content on my web application?

I had already spent a significant amount of time developing my skill set building front-end applications. Would I now have to learn something like WordPress to build apps?

Headless CMS has entered the chat.

Headless CMS, like Contentful, are essentially web applications that abstract away the database/backend from developers and non-developers alike.

A headless CMS does not provide a front-end. — They do provide developers with an API to get content from the back-end, and a user interface for non-developers to enter content into the back-end.

We will build an Angular application to display data and use Contentful to create/manage that data.

Contentful Basics

We will cover the basics of Contentful. — For a comprehensive introduction see here [2].

Contentful Overview

As an example, let’s set up a new Space with a Single Content Type in five steps.

1. Create a Space

Getting started is as simple as signing up. — Once signed up, we can create our own Space. As an analogy, we can think of a Space like our own individual database.

Top-Left Menu: Create Space

2. Create a Content Type

We will add a Content Type to our Space. We can think of a Content Type like a table definition in a Database. — A Content Type is not the actual content, just the design.

Create a Content Type

3. Create Fields

Now we will add fields to our Content Type. Think of fields like columns in a database table. — In our example, we are creating a blog post, which will have fields such as title, description, body, etc…

Add Fields to the Content Type

4. Create Content

Each piece of Content we add will be similar to a new row in a database. We will fill out each field we defined earlier in our blogPost Content Type.

Create new Content

5. Access the API

In the next section, we will use our Space ID and Content Delivery Access Token to retrieve our Contentful data and display it in our application.

Space ID & Content Delivery Acess Token

Angular: Accessing & Displaying Content

To get started with the Contentful API, we add the following object to our environment.ts file. We enter the information from step 5 of Contentful Basics.

environment.ts

1. Display All Entries of a Content Type

Using cdaClient.getEntries(content_type) , we retrieve a promise containing all Content for a specific Content Type. The resolved data is an array of blog posts. Each entry has two properties, fields and sys .

Sys contains information such as created-date and ID. Fields are the fields we defined in step 3 of Contentful Basics.

contentful.service.ts — 1.1

Leveraging the Angular Structural Directive, *ngFor , we can dynamically add all blog posts to the DOM. — When we add a new blog post to Contentful, our post will be automatically added by our Contentful Service.

Using Angular Template Syntax, we can build list items displaying info from our Contentful Service such as createdAt, ID, title, description, etc…

main.component.html — 1.2

2. Display a specific Entry of a Content Type

Using cdaClient.getEntry(id) , we can query a specific entry from our Contentful data. The resolved data is a single blog post with the sys and fields properties.

contentful.service.ts — 2.1

When a user clicks one of the containers from the first section, the router navigates to a dynamic route /posts/:id . In snippet 1.2, we passed the ID as a parameter via routerLink.— We can retrieve the ID from Angular’s ActivatedRoute paramMap .

post.component.ts — 2.2

app-routing.module.ts — 2.3

Contentful provides a Markdown editor for all text fields. We will leverage this by converting the Markdown to HTML and setting the inner HTML on a div. [4]

Use innerHTML judiciously, If we do not have full control over what is being entered into the innerHTML we need to sanitize the input to prevent xss-attacks [5].

post.component.ts — 2.4

Using Angular’s Structural Directive, *ngIf , we can optionally display a field if it exists. In our example, we will display a link to an original publication if present.

3. Add a New Contentful Entry

After publishing a new Contentful Entry, our application is immediately updated on refresh with the latest Content. — No changes are needed to our Angular project.

Final Product

Hosting

The live demo is hosted with Firebase. For directions on hosting a project with Firebase see here [6]. For alternative forms of hosting see here [7].