Angular

How to integrate Stackbit in your Angular-based website

How to use

Define ssgName: angular in your Stackbit configuration file.

By default, Stackbit will launch the Angular development server by running:

  • 1
npm run config --if-present && ./node_modules/.bin/ng serve  --port {PORT} --disable-host-check

If you have a config script defined in your package.json file, it will get run. This allows you to perform pre-bundling tasks such as baking needed environment variables into your environment.ts file.

For example, if you're using an API-based CMS with your Stackbit project, you should either configure npm run config to run a script that bakes the current CMS settings and keys into environment.ts (example) or adopt an alternative solution.

If you need to override how your site's development server gets run, define devCommand in your Stackbit configuration file.

Content reload

There is no out-of-the-box mechanism to gracefully refresh any page in any Angular webapp. Thus, to implement content reload you will need to have a listener to the stackbitObjectsChanged window event (reference).

Here's a technique you can use to encapsulate the implementation details inside your service classes, so that consumer components get automatically refreshed on content changes:

First, add a service class (e.g. StackbitService) which listens on the stackbitObjectsChanged window event and allows other services to subscribe to these events via an rxjs Subject object. Here's how the class looks like:

  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
import { Injectable } from '@angular/core'
import { Subject } from 'rxjs'

export class StackbitEvent {
  changedContentTypes: string[]
  changedObjectIds: []
  currentPageObjectId: string
  currentUrl: string
  visibleObjectIds: []
}

@Injectable()
export class StackbitService {
  public contentChanged = new Subject<StackbitEvent>()

  constructor() {
    window.addEventListener(
      'stackbitObjectsChanged',
      (event: any) => {
        this.contentChanged.next({
          changedContentTypes: event.detail.changedContentTypes,
          changedObjectIds: event.detail.changedObjectIds,
          // ...copy rest of properties
        })

        event.preventDefault()
      },
      { passive: false },
    )
  }
}

(source)

Then, in your existing services providing data to components, wrap the return value of your public methods with a BehaviorSubject. This will allow pushing updates to clients.

  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
import { Injectable } from '@angular/core'
import { BehaviorSubject } from 'rxjs'
import { StackbitEvent, StackbitService } from './stackbit.service'
// ...

@Injectable()
export class ContentfulService {
  constructor(private stackbitService: StackbitService) {
    // ...
  }

  getProduct(slug: string): BehaviorSubject<Promise<Entry<any>>> {
    const productSubject = new BehaviorSubject(this.getProductFromContentful(slug))
    this.stackbitService.contentChanged.subscribe({
      next: (event: StackbitEvent) => {
        productSubject.next(this.getProductFromContentful(slug))
      },
    })
    return productSubject
  }

  // ...
}

(source)

Managed hosting

When you're our Managed Hosting, include a Netlify configuration file (example).

Example

Angular + Contentful Starter
Based on Contentful's "Product Catalogue" example (GitHub) with added Stackbit support & updated to the latest version of Angular (v14 at the time of writing).