Configuration
Global settings
You can optionally set up global parsers and options shared between all DynamicHooksComponent
s in your app by using the provideDynamicHooks
function in your app providers.
import { ApplicationConfig } from '@angular/core';
import { provideDynamicHooks } from 'ngx-dynamic-hooks';
export const appConfig: ApplicationConfig = {
providers: [
provideDynamicHooks(...)
]
};
It accepts a DynamicHooksSettings
-object with the following properties:
Name | Type | Description |
---|---|---|
parsers |
HookParserEntry[] |
An list of hook parsers to provide to all DynamicHooksComponent s |
options |
ParseOptions | An options object to provide to all DynamicHooksComponent s |
inheritance |
number |
An enum option from DynamicHooksInheritance |
You can see an example here.
Child settings
You can provide additional parsers and options simply by calling provideDynamicHooks
again in the providers
-fields of child injector contexts, such on specific routes or even directly on components.
The child settings will be merged with other provided settings according to the value of the optional inheritance
property in the DynamicHooksSettings object. It accepts a value from the DynamicHooksInheritance
enum, which are as follows:
DynamicHooksInheritance.Linear
: (Default) Only merges with settings from direct ancestor injectors (such a father and grandfather injectors, but not “uncle” injectors).DynamicHooksInheritance.All
: Merges with settings from all injectors in the app.DynamicHooksInheritance.None
: Does not merge at all. Injector only uses own settings.
An example for using child settings might then look like this:
providers: [
...
provideDynamicHooks({
parsers: [ ... ],
options: { ... },
inheritance: DynamicHooksInheritance.None
})
]
DynamicHooksComponent
These are all of the inputs you can pass to each DynamicHooksComponent
(<ngx-dynamic-hooks>
) individually:
Input name | Type | Description |
---|---|---|
content |
any |
The content to parse and render. Can be a string or HTML element. |
context |
any |
An optional object to pass data to the dynamically-loaded components |
globalParsersBlacklist |
string[] |
An optional list of global parsers to blacklist, identified by their name |
globalParsersWhitelist |
string[] |
An optional list of global parsers to whitelist, identified by their name |
parsers |
HookParserEntry[] |
An optional list of hook parsers to use instead of the global parsers |
options |
ParseOptions | An optional options object to use instead of the global options |
There is also an output you may subscribe to:
Output name | Type | Description |
---|---|---|
componentsLoaded |
Observable<LoadedComponent[]> |
Will trigger once all components have loaded (including lazy-loaded ones) |
Each LoadedComponent
from the output represents a dynamically-created component and contains some information you may find interesting:
interface LoadedComponent {
hookId: number; // The unique hook id
hookValue: HookValue; // The hook that was replaced by this component
hookParser: HookParser; // The associated parser
componentRef: ComponentRef<any>; // The created componentRef
}
ParseOptions
You can define ParseOptions
whenever you parse content - either in the global settings, as an input to each DynamicHooksComponent
or as a parameter when using the library programmatically.
These options can be used to customize the parsing behaviour:
Option name | Type | Default | Description |
---|---|---|---|
sanitize |
boolean |
depends |
Whether to use Angular’s DomSanitizer to sanitize the content (hooks are unaffected by this). Defaults to true if content is a string, false if its an HTML element. |
convertHTMLEntities |
boolean |
true |
Whether to replace HTML entities like & with normal characters. |
fixParagraphTags |
boolean |
true |
When using a WYSIWYG-editor, enclosing text hooks may collide with its generated HTML (the <p> -tag starting before the hook and the corresponding </p> -tag ending inside, and vice versa). This will result in faulty HTML when rendered in a browser. This setting removes these ripped-apart tags. |
updateOnPushOnly |
boolean |
false |
Whether to update the bindings of dynamic components only when the context object passed to the DynamicHooksComponent changes by reference. |
compareInputsByValue |
boolean |
false |
Whether to deeply-compare inputs for dynamic components by their value instead of by their reference on updates. |
compareOutputsByValue |
boolean |
false |
Whether to deeply-compare outputs for dynamic components by their value instead of by their reference on updates. |
compareByValueDepth |
number |
5 |
When comparing by value, how many levels deep to compare them (may impact performance). |
triggerDOMEvents |
boolean |
depends |
Whether to emit CustomEvents from the component host elements when an output emits. The event name will be the output name. Defaults to true in standalone mode, otherwise false. |
ignoreInputAliases |
boolean |
false |
Whether to ignore input aliases like @Input('someAlias') in dynamic components and use the actual property names instead. |
ignoreOutputAliases |
boolean |
false |
Whether to ignore output aliases like @Output('someAlias') in dynamic components and use the actual property names instead. |
acceptInputsForAnyProperty |
boolean |
false |
Whether to disregard @Input() -decorators completely and allow passing in values to any property in dynamic components. Does not trigger ngOnChanges and can cause issues with change detection in zoneless mode. |
acceptOutputsForAnyObservable |
boolean |
false |
Whether to disregard @Output() -decorators completely and allow subscribing to any Observable in dynamic components. |
logOptions |
LogOptions |
{dev: true} |
Accepts a LogOptions object to customize when to log text, warnings and errors. |
Lazy-loading components
You can configure components to lazy-load only when its corresponding hook appears in the content. This reduces bundle sizes and saves bandwidth if the hook does not appear at all.
Using this feature is easy: Instead of using the component class directly, use a function that returns a promise with the component class instead. This works similar to lazy-loading routes in Angular.
You can put that function in the component
-field of a SelectorHookParserConfig. You also need to manually specify a selector, as it cannot be known before loading the component class, like so:
import { Component } from '@angular/core';
import { DynamicHooksComponent } from 'ngx-dynamic-hooks';
@Component({
...
imports: [DynamicHooksComponent]
})
export class AppComponent {
content = 'Load a component here: <app-lazy></app-lazy>';
parsers = [
{
component: () => import('./components/lazyComponent').then(m => m.LazyComponent),
selector: 'app-lazy'
}
]
}
<ngx-dynamic-hooks [content]="content" [parsers]="parsers"></ngx-dynamic-hooks>
That’s all there is to it! LazyComponent
will now be lazily-loaded if <app-lazy>...</app-lazy>
is found in the content.
Tip: It you are using a custom parser, you can return the lazy-loading function as part of loadComponent()
instead.
Note that it must be a function that returns a promise, not the promise itself! Otherwise the promise would be executed right where it is defined, which defeats the point of lazy-loading.
Alternate platforms
The default implementation of the library should work in both browsers as well as during server-side-rendering. However, there may be more specialized use cases on platforms that are not directly supported.
In such cases, you can create your own PlatformService
. The PlatformService
is internally used as a layer of abstraction between the library and the platform it runs on. It offers several functions to interact with the platform and handles platform-specific objects (such as document
and HTMLElement
in the case of the default PlatformService
).
You can implement your own PlatformService
by creating a class that follows the PlatformService interface and pass it as the second parameter to provideDynamicHooks
.
Tip: You can partially implement as many methods as you need. For all non-implemented methods, the library falls back to the default implementation.