{"id":13535491,"url":"https://github.com/lacolaco/ng-dynamic","last_synced_at":"2025-04-02T01:31:00.274Z","repository":{"id":57167904,"uuid":"73668138","full_name":"lacolaco/ng-dynamic","owner":"lacolaco","description":"dynamic contents projection in Angular","archived":true,"fork":false,"pushed_at":"2019-05-17T13:54:18.000Z","size":54,"stargazers_count":132,"open_issues_count":18,"forks_count":34,"subscribers_count":16,"default_branch":"master","last_synced_at":"2024-05-12T23:42:21.859Z","etag":null,"topics":["angular"],"latest_commit_sha":null,"homepage":"","language":"TypeScript","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":null,"status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/lacolaco.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":null,"code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null}},"created_at":"2016-11-14T04:53:15.000Z","updated_at":"2023-07-25T00:48:59.000Z","dependencies_parsed_at":"2022-09-12T19:03:54.251Z","dependency_job_id":null,"html_url":"https://github.com/lacolaco/ng-dynamic","commit_stats":null,"previous_names":["laco0416/ng-dynamic"],"tags_count":0,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/lacolaco%2Fng-dynamic","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/lacolaco%2Fng-dynamic/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/lacolaco%2Fng-dynamic/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/lacolaco%2Fng-dynamic/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/lacolaco","download_url":"https://codeload.github.com/lacolaco/ng-dynamic/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":246738497,"owners_count":20825789,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["angular"],"created_at":"2024-08-01T08:00:57.263Z","updated_at":"2025-04-02T01:31:00.024Z","avatar_url":"https://github.com/lacolaco.png","language":"TypeScript","readme":"# THIS REPOSITORY IS NOT MAINTAINED\n\n# ng-dynamic\n\n## Since Angular 4.0, AoT compiler cannot coexist with JiT compiler. If you want to use DynamicComponentModule, you cannot use AoT compilation.\n\nDynamic Content Projection in Angular 2+ \n\n[![npm version](https://badge.fury.io/js/ng-dynamic.svg)](https://badge.fury.io/js/ng-dynamic)\n[![CircleCI](https://circleci.com/gh/lacolaco/ng-dynamic/tree/master.svg?style=svg)](https://circleci.com/gh/lacolaco/ng-dynamic/tree/master)\n\n```\n$ npm install --save ng-dynamic\n```\n\n**Live Demo**: [Plunker](https://plnkr.co/edit/uzcYiN?p=preview)\n\n---\n\n## 'dynamic' means...\n\nWe 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.\n\n```ts\n@Component({\n  selector: 'html-preview',\n  template: '\u003cdiv [innerHTML]=\"html\"\u003e\u003c/div\u003e',\n})\nexport class HTMLPreviewComponent {\n  @Input() html: string;\n}\n```\n\nThis code has some problems:\n\n- `[innerHTML]` will sanitize its value and strip some elements.\n- in innerHTML, any Angular components like `\u003cmy-button\u003e` don't work.\n\n**ng-dynamic** can solve these problems by using standard Angular APIs and some _hacks_.\n\n### `\u003cdynamic-html [content]=\"html\"\u003e`\n\n`\u003cdynamic-html\u003e` is a component to render given HTML string and **mount** components in the HTML.\n\nExample: \n\n```ts\n@Component({\n  selector: 'my-button',\n  template: `\u003cbutton (click)=\"onClick()\"\u003eClick Me\u003c/button\u003e`\n})\nexport class MyButtonComponent {\n  onClick() {\n  }\n}\n\n@Component({\n  selector: 'my-app',\n  template: `\n    \u003cdynamic-html [content]=\"content\"\u003e\u003c/dynamic-html\u003e\n  `\n})\nexport class AppComponent {\n  content = `\n  \u003carticle\u003e\n    \u003ch1\u003eAwesome Document\u003c/h1\u003e\n    \u003cdiv\u003e\n      \u003cp\u003ebla bla bla\u003c/p\u003e\n      \u003cmy-button\u003e\u003c/my-button\u003e\n    \u003c/div\u003e\n  \u003c/article\u003e\n  `;\n}\n\n@NgModule({\n  imports: [\n    DynamicHTMLModule.forRoot({\n      components: [\n        { component: MyButtonComponent, selector: 'my-button' },\n      ]\n    })\n  ],\n  declarations: [AppComponent, MyButtonComponent],\n  bootstrap: [AppComponent]\n})\nexport class AppModule {\n}\n```\n\nResult: \n\n```html\n\u003cmy-app\u003e\n    \u003cdynamic-html\u003e\n      \u003carticle\u003e\n        \u003ch1\u003eAwesome Document\u003c/h1\u003e\n        \u003cdiv\u003e\n          \u003cp\u003ebla bla bla\u003c/p\u003e\n          \u003cmy-button\u003eClick Me\u003c/my-button\u003e\n        \u003c/div\u003e\n      \u003c/article\u003e\n    \u003c/dynamic-html\u003e\n\u003c/my-app\u003e\n```\n\n`\u003cmy-button\u003e` is resolved as `MyButtonComponent`.\n\n#### `DynamicHTMLModule`\n\nTo use `\u003cdynamic-html\u003e`, you have to import `DynamicHTMLModule` with `forRoot` static method.\nIts argument is a `DynamicHTMLOptions` object:\n\n```ts\n/**\n * defines dynamic-projectable components \n * \n * ```ts\n * @Component({\n *     selector: 'child-cmp',\n *     template: `\u003cp\u003echild:{{text}}\u003c/p\u003e`,\n * })\n * class ChildCmp { \n *     @Input() text: string;\n * }\n * \n * DynamicHTMLModule.forRoot({\n *   components: [\n *     { component: ChildCmp, selector: 'child-cmp' } },\n *   ]\n * })\n * ```\n */\nexport interface ComponentWithSelector {\n    /**\n     * component's selector\n     */\n    selector: string;\n    /**\n     * component's type\n     */\n    component: Type\u003cany\u003e;\n}\n\n/**\n * options for DynamicHTMLModule\n */\nexport class DynamicHTMLOptions {\n    /**\n     * identifies components projected in dynamic HTML.\n     */\n    components: Array\u003cComponentWithSelector\u003e;\n}\n```\n\n#### `OnMount` Lifecycle method\n\n```ts\n/**\n * Lifecycle hook that is called after instantiation the component. \n * This method is called before ngOnInit.\n */\nexport abstract class OnMount {\n    abstract dynamicOnMount(attrs?: Map\u003cstring, string\u003e, innerHTML?: string, element?: Element): void;\n}\n```\n\n`OnMount` allows you to create component has _hybrid content projection_.\n_hybrid content projection_ means that the component can project its content from even _static_ template or _dynamic_ HTML. \n\nSee also demo.\n\n```ts\n@Component({\n  selector: 'awesome-button',\n  template: `\u003cbutton (click)=\"onClick()\" #innerContent\u003e\u003cng-content\u003e\u003c/ng-content\u003e\u003c/button\u003e`,\n})\nexport class AwesomeButtonComponent implements OnMount, OnInit {\n  @Input() msg: string;\n  @ViewChild('innerContent') innerContent: ElementRef;\n\n  dynamicOnMount(attr: Map\u003cstring, string\u003e, content: string) {\n    this.msg = attr.get('msg');\n    this.innerContent.nativeElement.innerHTML = content;\n    console.log(`onMount: ${this.msg}`);\n  }\n\n  ngOnInit() {\n    console.log(`onInit: ${this.msg}`);\n  }\n\n  onClick() {\n    console.log('clicked');\n  }\n}\n```\n\n#### `\u003cdynamic-html\u003e` Constraints\n\n- `[content]` is **not a template**. so it cannot resolve `{{foo}}`, `*ngIf` and any template syntax.\n\n### `*dynamicComponent=\"template\"`\n\n`dynamicComponent` is a directive to create dynamic component which has the template.\n\nExample: \n\n```ts\n@Component({\n  selector: 'dynamic-cmp-demo',\n  template: `\n    \u003cdiv *dynamicComponent=\"template; context: {text: text};\"\u003e\u003c/div\u003e\n  `,\n})\nexport class DynamicCmpDemoComponent {\n  template = `\n  \u003carticle\u003e\n    \u003ch1\u003eAwesome Document\u003c/h1\u003e\n    \u003cdiv\u003e\n      \u003cp\u003e{{text}}\u003c/p\u003e\n      \u003cmy-button\u003e\u003c/my-button\u003e\n    \u003c/div\u003e\n  \u003c/article\u003e\n  `;\n\n  text = 'foo';\n}\n\n@NgModule({\n  imports: [\n    CommonModule,\n  ],\n  declarations: [\n    MyComponent\n  ],\n  exports: [\n    MyComponent\n  ]\n})\nexport class SharedModule { }\n\n@NgModule({\n  imports: [\n    BrowserModule,\n    FormsModule,\n    SharedModule,\n    DynamicComponentModule.forRoot({\n      imports: [SharedModule]\n    }),\n  ],\n  declarations: [\n    AppComponent,\n    DynamicCmpDemoComponent,\n  ],\n  bootstrap: [AppComponent]\n})\nexport class AppModule {\n}\n```\n\nResult: \n\n```html\n\u003cmy-app\u003e\n    \u003cng-component\u003e\n      \u003carticle\u003e\n        \u003ch1\u003eAwesome Document\u003c/h1\u003e\n        \u003cdiv\u003e\n          \u003cp\u003efoo\u003c/p\u003e\n          \u003cmy-button\u003eClick Me\u003c/my-button\u003e\n        \u003c/div\u003e\n      \u003c/article\u003e\n    \u003c/ng-component\u003e\n\u003c/my-app\u003e\n```\n\n`\u003cmy-button\u003e` is resolved as `MyButtonComponent`.\n\n#### `DynamicComponentModule`\n\nTo use `dynamicComponent`, you have to import `DynamicComponentModule` with `forRoot` static method.\nIts argument is a `NgModule` metadata object:\n\n```ts\n/**\n * Setup for DynamicComponentDirective\n * \n * ```ts\n * @NgModule({\n *   imports: [\n *     DynamicComponentModule.forRoot({\n *       imports: [CommonModule]\n *     })\n *   ],\n * })\n * class AppModule {}\n * ```\n */\n```\n\n#### `dynamicComponent` Constraints\n\n`dynamicComponent` needs `JitCompiler`. You cannot use AoT compilation with DynamicComponentModule.\n\n## License\nMIT\n\n## Developing\n\n```\nnpm i \u0026\u0026 npm run demo # and open http://localhost:8080\n```\n\nContributions welcome!","funding_links":[],"categories":["Uncategorized","TypeScript"],"sub_categories":["Uncategorized"],"project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Flacolaco%2Fng-dynamic","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Flacolaco%2Fng-dynamic","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Flacolaco%2Fng-dynamic/lists"}