@fgeo/bloomreach-experience-ng-sdk
v0.3.2-rc8
Published
SDK for powering content and components in Angular applications by [BloomReach Experience](https://www.bloomreach.com/en/products/experience). This library makes integrating an Angular app with BloomReach Experience a breeze. It supports both client-sid
Downloads
6
Readme
Bloomreach Experience SDK for Angular
SDK for powering content and components in Angular applications by BloomReach Experience. This library makes integrating an Angular app with BloomReach Experience a breeze. It supports both client-side- and server-side rendered/universal Angular apps.
BloomReach Experience allows you to use an external front-end such as Angular for rendering while still providing a native-like authoring experience, such as integrated preview, in-context editing, drag & drop, server-side personalization. For more information on this approach, see A new approach to integrating SPA's with WCM: Fixing what's wrong with headless integrations.
Install
npm install bloomreach-experience-ng-sdk jsonpointer path-to-regexp --save
Please note that since it's not a best practice to include 3rd party libraries with an Angular library, the 3rd party libraries have to be installed manually as done with the above command.
Usage
Add the SDK to the app's NgModule imports:
import { BloomreachExperienceNgSdkModule } from 'bloomreach-experience-ng-sdk';
@NgModule({
imports: [
// ... other imports
BloomreachExperienceNgSdkModule
],
...
Then, add the following to an Angular component where you want BloomReach to (partly) determine what to render:
- Import
ApiUrlsService
,ComponentMappingsService
,InitializeSdkService
, andRequestContextService
; - Add these services to the constructor of the component;
- Override default API Urls using
ApiUrlsService
; - Set component mappings through
ComponentMappingsService
; - Set current URL-path via
RequestContextService
; - Call
initialize()
method ofInitializeSdkService
; - And add
<bre-render-cms-component></bre-render-cms-component>
to the component template.
See the next paragraph for a description and explanation of each of the services and the components. There's also an API section below that includes more details.
import { Component, OnInit } from '@angular/core';
import { Router } from '@angular/router';
import { ApiUrlsService, ComponentMappingsService, InitializeSdkService, RequestContextService } from 'bloomreach-experience-ng-sdk';
@Component({
template: `<bre-render-cms-component></bre-render-cms-component>`,
})
export class MyAppClass implements OnInit {
componentMappings = {
"MyCustomComponent": MyCustomComponent
};
apiUrls = {
live: {
// override live API URL here
},
preview: {
// override preview API URL here
}
}
constructor(
private router: Router,
private apiUrlsService: ApiUrlsService,
private componentMappingsService: ComponentMappingsService,
private initializeSdkService: InitializeSdkService,
private requestContextService: RequestContextService
) {}
ngOnInit() {
this.apiUrlsService.setApiUrls(this.apiUrls);
this.componentMappingsService.setComponentMappings(this.componentMappings);
this.requestContextService.parseUrlPath(this.router.url);
this.initializeSdkService.initialize();
}
}
The component mappings tell the Angular app what Angular components to use for rendering
components from the Page Model API response, by mapping these to the hst:label of a CMS
catalog component. These mappings are set through the ComponentMappingsService
.
The RequestContextService
is used to pass the current URL so that it can fetch the Page
Model for the page that is active; and to detect whether preview is active so that
meta-data for CMS' Channel Manager functionality (e.g. in-context editing) is included in
the HTML, and consequently Channel Manager functionality is enabled.
InitializeSdkService
fetches the Page Model for the current URL that is set through
RequestContextService
. and it initializes the CMS' Channel Manager integration.
Finally, <bre-render-cms-component>
renders the components and any content referenced
from the components in the Page Model API response. This tag/component should be placed in
the Angular app at the exact location where you want the CMS components to be outputted.
Demo
A demo project is available at Github. Please note that in order to use the Channel Manager Integration, you need to have an Enterprise Maven account, which is only available toBloomReach's Enterprise customers.
The demo project can be used in combination with the Angular example app. To build and run the example app, do the following:
npm install
npm run start
The demo project is configured for React by default, so you will have to update the CORS headers from http://localhost:3000 to http://localhost:4200 in /hst:hst/hst:hosts/dev-localhost/localhost/hst:root[@hst:responseheaders]. Also, make sure to change the Channel Settings in the Channel Manager, and select Angular from the front-end renderer dropdown menu.
Creating custom components
Custom components that are rendered through <bre-render-cms-component>
can be created
just as any other regular Angular component, with the requirement that it should implement
the BaseComponent
interface that is provided by the SDK.
Additionally, all components that are rendered through <bre-render-cms-component>
should
be added to the @NgModule()
's entryComponents
array, as the components are created
using the componentFactory. Otherwise you will get an error during component rendering.
Properties
The following properties are passed to the component, provided it's rendered by
<RenderCmsComponent>
:
configuration
-Object
component configuration. Contains the contributed models, raw parameters and resolved parameters. Content included in the component's model is not serialized as part of the component's configuration but in a separate content object, and a JSON Pointer reference is used to link to the actual content object. This is done to prevent content from being included multiple times in the API response when referenced multiple times on a page.
Example
import { Component, Input, OnInit } from '@angular/core';
import { BaseComponent, getNestedObject } from 'bloomreach-experience-ng-sdk';
@Component({
selector: 'app-news-list',
templateUrl: `
<div class="row" *ngIf="items; else configureComponentBlock">
<div class="col-sm-12 news-list">
<app-news-item *ngFor="let item of items" [contentRef]="item"></app-news-item>
</div>
<nav class="blog-pagination">
<span class="btn btn-outline-primary disabled">Older</span>
<span class="btn btn-outline-secondary disabled">Newer</span>
</nav>
</div>
<ng-template #configureComponentBlock>Click to configure {{configuration.label}}</ng-template>`,
styleUrls: ['./news-list.component.css']
})
export class NewsListComponent implements BaseComponent, OnInit {
@Input() configuration: any;
items: any;
constructor() { }
ngOnInit() {
this.createList();
}
createList() {
this.items = getNestedObject(this.configuration, ['models', 'pageable', 'items']);
}
}
Content components
Components that reference a single content-item (e.g. the Banner component) can use a superclass that provides a convenient method for retrieving the corresponding content-item based on the reference found in the component's configuration.
To use the superclass, a content component has to extend SingleContentComponent
, which
is provided by the SDK. Just as a regular custom component, the component will need to
implement the BaseComponent
interface.
The SingleContentComponent
provides two methods: getContent()
and
getImageUrl(imageRef)
. See more details below.
Finally, content components can use the <bre-cms-edit-button>
component for rendering
the Manage Content
Button
in preview mode in the CMS.
Properties
content
-Object
raw content object that contains the content-item's fields and field-values. Any references to other content-items (e.g. images) are serialized as JSON Pointers.
Methods
getContent
-Object
retrieves the component's referenced content-item using the JSONPointer that is found in the component's configuration. Stores the content-item object in thecontent
property.getImageUrl(imageRef: string)
-String
generates fully qualified URL to an image using the JSONPointer reference to the image.
Example
import { Component, OnInit } from '@angular/core';
import { BaseComponent, ImageUrlService, PageModelService, SingleContentComponent } from 'bloomreach-experience-ng-sdk';
@Component({
selector: 'app-banner',
templateUrl: `
<div class="jumbotron has-edit-button" *ngIf="content; else configureComponentBlock">
<bre-cms-edit-button *ngIf="content" [configuration]="content"></bre-cms-edit-button>
<h1>{{content.title}}</h1>
<figure>
<img src={{imageUrl}} alt={{content.title}}/>
</figure>
<p [innerHTML]="content.content.value"></p>
</div>
<ng-template #configureComponentBlock>Click to configure {{configuration.label}}</ng-template>`,
styleUrls: ['./banner.component.css']
})
export class BannerComponent extends SingleContentComponent implements BaseComponent, OnInit {
imageUrl: string;
constructor(imageUrlService: ImageUrlService, pageModelService: PageModelService) {
super(imageUrlService, pageModelService);
}
ngOnInit() {
super.ngOnInit();
this.getImage();
}
getImage() {
if (this.content && this.content.image) {
this.imageUrl = super.getImageUrl(this.content.image);
}
}
}
Static CMS components
Static CMS components are components that are defined by developers / administrators and cannot be modified by users in the CMS. However, any content or site menus these components reference can be changed by users in the CMS.
Since <RenderCmsComponent>
only renders container components (drag-and-drop components)
by default, you have to specify two additional properties in order to render a static CMS
component:
path
property to point to the relative path of the component;renderComponent
property to specify which Angular component to use for rendering the component. See the example below.
import { Component } from '@angular/core';
import { MenuComponent } from '../cms-components/menu/menu.component';
@Component({
selector: 'app-static-component-example',
templateUrl: `<bre-render-cms-component [path]="'menu'" [renderComponent]="menuComponent"></bre-render-cms-component>`,
styleUrls: ['./static-component-example.css']
})
export class StaticComponentExample {
menuComponent = MenuComponent;
}
More component examples
For more detailed examples, see the components included in the demo application.
Building the SDK
You can build the SDK using the following command:
ng build --prod bloomreach-experience-ng-sdk
To test out builds locally, you can use the example application that you can build and run from the root:
npm install
npm run start
API
ApiUrlsService
Service for overriding the default API URLs, which are used for fetching the Page Model API. Uses both a live and preview URL for the API URL.
Methods
setApiUrls(newApiUrls: ApiUrls = {})
-None
allows you to override the default URLs. Typically you will only have to definescheme
,hostname
,port
, andcontextPath
. SeeApiUrls
type below for format of thenewApiUrls
parameter.
ApiUrls
type
live
:scheme
:String
scheme (default: http)hostname
:String
hostname (default: localhost)port
:number
port number (default: 8080)contextPath
:String
site context-path (default: site)channelPath
:String
path to the used channel, if channel is accessed through a subpathpreviewPrefix
:String
preview-prefix used by CMS (default: _cmsinternal)apiPath
:String
path to Page Model API as subpath (default: resourceapi)apiComponentRenderingUrlSuffix
:String
(default: _hn:type=component-rendering&_hn:ref=)
preview
: same as live (see above)
ComponentMappingsService
The component mapping maps CMS catalog components to Angular components, so that Angular knows what components to use for rendering the components in the Page Model API response.
Methods
setComponentMappings(componentMappings: ComponentMappings)
-None
sets the component mappings. Expects as input an object with thehst:label
of the CMS components as keys and as value the Angular component used for rendering the component.
Example
import { Component, OnInit } from '@angular/core';
import { ComponentMappingsService } from 'bloomreach-experience-ng-sdk';
export class ComponentMappingExampleComponent implements OnInit {
constructor(private componentMappingsService: ComponentMappingsService) {}
ngOnInit() {
const componentMappings = {
'Banner': BannerComponent
}
this.componentMappingsService.setComponentMappings(this.componentMappings);
}
}
ImageUrlService
Generates URLs to images for any images that are served directly from BloomReach Experience.
Methods
getImageUrl(imageRef)
-String
returns URL of image usingimageRef
, the JSON Pointer that references the image.getImageUrlByPath(imagePath: string, variant: string)
-String
returns URL of image using its relative-path and the name of the image-variant.
InitializeSdkService
Service that handles initialization of the SDK, including:
- Fetching initial Page Model via
PageModelService
, and updates to the Page Model on navigation changes or component updates in the CMS. - Initializating the Channel Manager integration.
- Restoring the Page Model state using Transfer State API. To use it import ServerTransferStateModule on the server and BrowserTransferStateModule on the client.
Methods
initialize({initializePageModel = true, initializeRouterEvents = true}): Subscription | void
- initializes the SDK by fetching the Page Model and initializing the Channel manager integration. Returns router events subscription or void ifinitializeRouterEvents
isfalse
.initializePageModel: boolean
- flag to fetch the Page Model on initialization;initializeRouterEvents: boolean
- flag to subscribe for router events.
PageModelService
Fetches the Page Model API and manages state.
Methods
getPageModel()
-Object
return the Page Model. Please note that this is a synchronous call, so if this is called during initialization, the Page Model might not have been set yet. UsegetPageModelSubject()
in these cases.setPageModel(value: any)
- update the Page Model and push the value to the Page Model subject (seegetPageModelSubject()
).getPageModelSubject()
Subject<Object>
return a subject of the Page Model that can be subscribed to for asynchronous access to the Page Model.getContentViaReference(contentRef: string)
-Object
returns content item from Page Model using thecontentRef
JSON Pointer.
RequestContextService
The RequestContextService
is used to get the current URL for fetching the Page Model for
the current page; and to detect whether preview mode is active so that meta-data for
Channel Manager functionality (e.g. in-context editing) is included in the HTML, and
consequently Channel Manager functionality is enabled.
Methods
parseUrlPath(urlPath: string): void
- parses the current URL-path for detecting the current URL and preview detection.parseRequest(request: Request): void
- parses the current request for detecting the current URL and preview detection. SeeRequest
type below for format of therequest
parameter.isPreviewRequest(): boolean
- returns if preview mode is active/detected.getDebugging(): boolean
- returns if debugging mode is enabled or notsetDebugging(debugging: boolean): void
- sets debugging mode which enables detailed logging on request parsing, Channel Manager integration, and component updates.
Request
type
hostname: string
- should contain the hostname for the current request:window.location.hostname
for client-side rendering (Browser Platform);self.location.hostname
for Web Workers (Worker Platform);request.hostname
for server-side rendering (Server Platform/Angular Universal). For server-side rendering, the SDK expects the request to be injected asREQUEST
token:import { REQUEST } from 'bloomreach-experience-ng-sdk'; // ... providers: [ { provide: REQUEST, useValue: request }, ], // ...
path: string
- should contain the URL-path for the current request (client-side this is window.location.pathname).
<bre-render-cms-component>
Renders a CMS component and all of its children using the Page Model supplied by
PageModelService
. Will render the entire Page Model by default.
Properties
path
-String
path to a component (static CMS component), container or container-item in the Page Model to render only that component and its children. If no path is supplied, entire Page Model will be rendered.renderComponent
-Angular.Component
render a static CMS component using specified Angular component. Only works in combination withpath
property, which should specify path to the static CMS component. Site menus that are rendered this way can leverage the<bre-cms-edit-button>
component for rendering edit buttons in the CMS.
Example
import { Component } from '@angular/core';
import { MenuComponent } from '../cms-components/menu/menu.component';
@Component({
selector: 'app-static-component-example',
templateUrl: `<bre-render-cms-component [path]="'menu'" [renderComponent]="menuComponent"></bre-render-cms-component>`,
styleUrls: ['./static-component-example.css']
})
export class StaticComponentExample {
menuComponent = MenuComponent;
}
<bre-cms-edit-button>
Inserts meta-data for either a content-item or site menu for placing an edit button in preview mode in the CMS.
Properties
configuration
-Object
configuration of the content-item or site-menu (not the component configuration containing the content-item/site-menu), which has the_meta
object in its root.
Example
<bre-cms-edit-button *ngIf="menuConfiguration" [configuration]="menuConfiguration"></bre-cms-edit-button>
getNestedObject(nestedObject, pathArray)
Returns a nested object or value using a path array. Useful when you need to access deeply nested objects/values without having to string null checks together.
Arguments
nestedObject
-Object
the object containing the nested object or value.pathArray
-Array
contains the path to the nested object as an array.
Return types
Object|null
returns the nested object if found, otherwise returns null.
FAQ / Troubleshooting
Nothing here yet :)
License
Apache 2.0