The Fastest Way To Build Lightweight Angular Content Service

The Best Solutions Are Simple!

ยท

5 min read

The Fastest Way To Build Lightweight Angular Content Service

In the typical Angular applications, we use a lot of titles, labels, headers, and more content. But if you need a way to put those content elements in one place, you need something like a dictionary. It's a combination of small words and more extensive sentences.

Some applications need multiple languages, but others need one language but have loads of content to re-use. In this article, I want to show you the fastest way to create a content (some call it a dictionary) Service for your Angular application.

If you need a content service with multiple languages, I highly recommend NGX-Translate. This package offers a simple API and Pipe mechanism to re-use pieces of content but also supports multiple languages.

divider-byrayray.png

Result

If you don't like reading, check out my example on StackBlitz and copy-and-paste it ๐Ÿ˜†.

Create A Content Service

The simplest and fastest way to create Angular Services is by using the Angular CLI.

ng generate service services/content

By running this command, you will generate an Angular Service, automatically added to the app.module.ts file. If your project has different settings for the CLI, it could appear in another Angular Module.

Now the Content Service looks like this.

import { Injectable } from '@angular/core';

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

divider-byrayray.png

Create A JSON Dictionary File

You need to create a dictionary file to put in all your titles, labels, and other content. Please put it in a place that works best for your application.

I create a dictionary folder where I make the general.dictionary.json file, but I can have more dictionary files there.

The content I put in there looks like this.

{
   "pages" : {
       "home": {
            "title" : "Home",
            "name" : "Company name"
        }
   }
}

You can create any structure you like; it's up to you what works best.

divider-byrayray.png

Prepare Content Service For Re-usability

We start with creating a private property cache$ where we make a BehaviourSubject. We do this because we can subscribe to this BehaviourSubject from any place in the application. And the best part is, when a content item is being updated, it will automatically be updated everywhere.

I create a StackBlitz and a Github example, to show why the BehaviourSubject is an important part of the service.

private cache$: BehaviorSubject<any> = new BehaviorSubject(null);

If you wonder what the difference is between different Subjects, please check this post "When Use RxJS Subject, BehaviourSubject, ReplaySubject, AsyncSubject, or Void Subject in Angular"

The next step is importing the dictionary file on the top.

import content from '../dictionary/general.dictionary.json';

In the constructor of the Service, we want to make sure that if the BehaviourSubject is null, we need to add the content from the dictionary file.

constructor() {
     if (this.cache$.getValue() === null) {
         this.cache$.next(content);
     }
}

Now we need a method that exposes the BehaviourSubject with its content to the subscribers. We do that by returning the cache$ property. The return type of the method is any for this case because you don't have to type the structure of your dictionary. But if you want to, you can do it.

public content(): BehaviorSubject<any> {
    return this.cache$;
}

For making the Service great for usage in your HTML templates, we can expose the content() method with the .getValue() method chained to it.

public value(): any {
     return this.content()?.getValue();
}

Now we have everything in our Service to make it usable. The complete code of the Service looks like this. Simple right ๐Ÿ˜‰.

import { Injectable } from '@angular/core'
import { BehaviorSubject } from 'rxjs'
import content from '../dictionary/general.dictionary.json'

@Injectable({
    providedIn: 'root'
})
export class ContentService {
    private cache$: BehaviorSubject<any> = new BehaviorSubject(null)

    constructor() {
        if (this.cache$.getValue() === null) {
            this.cache$.next(content)
        }
    }

    public content(): BehaviorSubject<any> {
        return this.cache$
    }

    public value(): any {
        return this.content()?.getValue()
    }
}

divider-byrayray.png

Use The Content Service In The Content

I guess you know how to make an Angular Component. The CLI is my favorite way to do it. For example, you generate a HomepageComponent.

ng generate component components/homepage

If you have an Angular Component for yourself, it's fine.

First, we need to import the ContentService into our Component and expose it via the constructor.

import { Component } from '@angular/core';

@Component({
    selector: 'homepage',
    templateUrl: './homepage.component.html',
    styleUrls: ['./homepage.component.scss']
})
export class HomepageComponent {
    constructor(private contentService: ContentService) {}
}

Now we want to expose the content from our ContentService to the HTML template. We create a content property in our Component and add the value via the constructor.

import { Component } from '@angular/core';

@Component({
    selector: 'homepage',
    templateUrl: './homepage.component.html',
    styleUrls: ['./homepage.component.scss']
})
export class HomepageComponent {
    public content: any = null
    constructor(private contentService: ContentService) {
        this.content = this.contentService.value()
        console.log('content:', content)
    }
}

Via the console.log, you can test if everything works as expected.

Now add the title from our dictionary file in the HTML template using the ContentService.

<header>
     <h1>{{content?.pages?.home?.title ?? 'title'}}</h1>
</header>

In the example, you can see that we add an expression to the template. In that expression, we are using the nullish collision technique. We do that, so we don't get error's when the property is not in the dictionary file. In this case, it just shows you "title". If the value is available, it will deliver the value.

divider-byrayray.png

Resources

Code Example in StackBlitz

Code Example in Github

divider-byrayray.png

Conclusion

Now you have a straightforward Content Service in Angular without using an external package. So it's lightweight and super fast, and that is the best thing about it. Often, we may be thinking too complicated, but all we need is something simple.

Hopefully, this helps you build great Angular applications that are easy to maintain.

divider-byrayray.png

Thanks!

hashnode-footer.png I hope you learned something new or are inspired to create something new after reading this story! ๐Ÿค— If so, consider subscribing via email (scroll to the top of this page) or follow me here on Hashnode.

Did you know that you can create a Developer blog like this one, yourself? It's entirely for free. ๐Ÿ‘๐Ÿ’ฐ๐ŸŽ‰๐Ÿฅณ๐Ÿ”ฅ

If I left you with questions or something to say as a response, scroll down and type me a message. Please send me a DM on Twitter @DevByRayRay when you want to keep it private. My DM's are always open ๐Ÿ˜

Did you find this article valuable?

Support Dev By RayRay by becoming a sponsor. Any amount is appreciated!

ย