Use Visual Editor with Angular
Learn how to use Visual Editor with an Angular-based website.
# Configure Visual Editor for an Angular project
Define ssgName: angular
in your Visual Editor configuration file.
By default, Visual Editor will launch the Angular development server by running:
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 run. This allows you to perform pre-bundling tasks such as copying needed environment variables into your environment.ts
file.
For example, if you're using an API-based CMS with your Visual Editor project, you should either configure npm run config
to run a script that copies 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 runs, define devCommand in your Visual Editor configuration file.
# Content reload
There is no out-of-the-box mechanism to gracefully refresh any page in an Angular web app. So, 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 are automatically refreshed on content changes:
First, add a service class (e.g. StackbitService
) that listens on the stackbitObjectsChanged
window event and allows other services to subscribe to these events via an RxJS Subject
object. For example:
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 that provide data to components, wrap the return value of your public methods with a BehaviorSubject
. This will allow pushing updates to clients.
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)
# Example
Angular + Contentful Starter — based on Contentful's "Product Catalogue" example (GitHub), with added Visual Editor support and updated to the latest version of Angular (v14 at the time of writing).
Did you find this doc useful?
Your feedback helps us improve our docs.