
Security News
Browserslist-rs Gets Major Refactor, Cutting Binary Size by Over 1MB
Browserslist-rs now uses static data to reduce binary size by over 1MB, improving memory use and performance for Rust-based frontend tools.
Dynamic Content Projection in Angular 2+
$ npm install --save ng-dynamic
Live Demo: Plunker
We often need to project some dynamic contents into your Angular app. For example, if you make a markdown editor, you want to display the rendererd preview.
@Component({
selector: 'html-preview',
template: '<div [innerHTML]="html"></div>',
})
export class HTMLPreviewComponent {
@Input() html: string;
}
This code has some problems:
[innerHTML]
will sanitize its value and strip some elements.<my-button>
don't work.ng-dynamic can solve these problems by using standard Angular APIs and some hacks.
<dynamic-html [content]="html">
<dynamic-html>
is a component to render given HTML string and mount components in the HTML.
Example:
@Component({
selector: 'my-button',
template: `<button (click)="onClick()">Click Me</button>`
})
export class MyButtonComponent {
onClick() {
}
}
@Component({
selector: 'my-app',
template: `
<dynamic-html [content]="content"></dynamic-html>
`
})
export class AppComponent {
content = `
<article>
<h1>Awesome Document</h1>
<div>
<p>bla bla bla</p>
<my-button></my-button>
</div>
</article>
`;
}
@NgModule({
imports: [
DynamicHTMLModule.forRoot({
components: [
{ component: MyButtonComponent, selector: 'my-button' },
]
})
],
declarations: [AppComponent, MyButtonComponent],
bootstrap: [AppComponent]
})
export class AppModule {
}
Result:
<my-app>
<dynamic-html>
<article>
<h1>Awesome Document</h1>
<div>
<p>bla bla bla</p>
<my-button>Click Me</my-button>
</div>
</article>
</dynamic-html>
</my-app>
<my-button>
is resolved as MyButtonComponent
.
DynamicHTMLModule
To use <dynamic-html>
, you have to import DynamicHTMLModule
with forRoot
static method.
Its argument is a DynamicHTMLOptions
object:
/**
* defines dynamic-projectable components
*
* ```ts
* @Component({
* selector: 'child-cmp',
* template: `<p>child:{{text}}</p>`,
* })
* class ChildCmp {
* @Input() text: string;
* }
*
* DynamicHTMLModule.forRoot({
* components: [
* { component: ChildCmp, selector: 'child-cmp' } },
* ]
* })
* ```
*/
export interface ComponentWithSelector {
/**
* component's selector
*/
selector: string;
/**
* component's type
*/
component: Type<any>;
}
/**
* options for DynamicHTMLModule
*/
export class DynamicHTMLOptions {
/**
* identifies components projected in dynamic HTML.
*/
components: Array<ComponentWithSelector>;
}
OnMount
Lifecycle method/**
* Lifecycle hook that is called after instantiation the component.
* This method is called before ngOnInit.
*/
export abstract class OnMount {
abstract dynamicOnMount(attrs?: Map<string, string>, innerHTML?: string, element?: Element): void;
}
OnMount
allows you to create component has hybrid content projection.
hybrid content projection means that the component can project its content from even static template or dynamic HTML.
See also demo.
@Component({
selector: 'awesome-button',
template: `<button (click)="onClick()" #innerContent><ng-content></ng-content></button>`,
})
export class AwesomeButtonComponent implements OnMount, OnInit {
@Input() msg: string;
@ViewChild('innerContent') innerContent: ElementRef;
dynamicOnMount(attr: Map<string, string>, content: string) {
this.msg = attr.get('msg');
this.innerContent.nativeElement.innerHTML = content;
console.log(`onMount: ${this.msg}`);
}
ngOnInit() {
console.log(`onInit: ${this.msg}`);
}
onClick() {
console.log('clicked');
}
}
<dynamic-html>
Constraints[content]
is not a template. so it cannot resolve {{foo}}
, *ngIf
and any template syntax.*dynamicComponent="template"
dynamicComponent
is a directive to create dynamic component which has the template.
Example:
@Component({
selector: 'dynamic-cmp-demo',
template: `
<div *dynamicComponent="template; context: {text: text};"></div>
`,
})
export class DynamicCmpDemoComponent {
template = `
<article>
<h1>Awesome Document</h1>
<div>
<p>{{text}}</p>
<my-button></my-button>
</div>
</article>
`;
text = 'foo';
}
@NgModule({
imports: [
CommonModule,
],
declarations: [
MyComponent
],
exports: [
MyComponent
]
})
export class SharedModule { }
@NgModule({
imports: [
BrowserModule,
FormsModule,
SharedModule,
DynamicComponentModule.forRoot({
imports: [SharedModule]
}),
],
declarations: [
AppComponent,
DynamicCmpDemoComponent,
],
bootstrap: [AppComponent]
})
export class AppModule {
}
Result:
<my-app>
<ng-component>
<article>
<h1>Awesome Document</h1>
<div>
<p>foo</p>
<my-button>Click Me</my-button>
</div>
</article>
</ng-component>
</my-app>
<my-button>
is resolved as MyButtonComponent
.
DynamicComponentModule
To use dynamicComponent
, you have to import DynamicComponentModule
with forRoot
static method.
Its argument is a NgModule
metadata object:
/**
* Setup for DynamicComponentDirective
*
* ```ts
* @NgModule({
* imports: [
* DynamicComponentModule.forRoot({
* imports: [CommonModule]
* })
* ],
* })
* class AppModule {}
* ```
*/
dynamicComponent
ConstraintsdynamicComponent
needs JitCompiler
. You can use AoT compilation, but you cannot eliminate the dependency on @angular/compiler
.
import 'core-js/shim'; // reflect-metadata polyfill
import 'zone.js/dist/zone';
import {platformBrowser} from '@angular/platform-browser';
import {COMPILER_PROVIDERS} from '@angular/compiler';
import {AppModuleNgFactory} from './app.module.ngfactory';
platformBrowser([
...COMPILER_PROVIDERS, // JitCompiler providers
]).bootstrapModuleFactory(AppModuleNgFactory);
MIT
npm i && npm run demo # and open http://localhost:8080
Contributions welcome!
FAQs
dynamic contents projection in Angular
The npm package ng-dynamic receives a total of 447 weekly downloads. As such, ng-dynamic popularity was classified as not popular.
We found that ng-dynamic demonstrated a not healthy version release cadence and project activity because the last version was released a year ago. It has 1 open source maintainer collaborating on the project.
Did you know?
Socket for GitHub automatically highlights issues in each pull request and monitors the health of all your open source dependencies. Discover the contents of your packages and block harmful activity before you install or update your dependencies.
Security News
Browserslist-rs now uses static data to reduce binary size by over 1MB, improving memory use and performance for Rust-based frontend tools.
Research
Security News
Eight new malicious Firefox extensions impersonate games, steal OAuth tokens, hijack sessions, and exploit browser permissions to spy on users.
Security News
The official Go SDK for the Model Context Protocol is in development, with a stable, production-ready release expected by August 2025.