GithubHelp home page GithubHelp logo

ng-dynamic's Introduction

THIS REPOSITORY IS NOT MAINTAINED

ng-dynamic

Since Angular 4.0, AoT compiler cannot coexist with JiT compiler. If you want to use DynamicComponentModule, you cannot use AoT compilation.

Dynamic Content Projection in Angular 2+

npm version CircleCI

$ npm install --save ng-dynamic

Live Demo: Plunker


'dynamic' means...

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.
  • in innerHTML, any Angular components like <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 Constraints

dynamicComponent needs JitCompiler. You cannot use AoT compilation with DynamicComponentModule.

License

MIT

Developing

npm i && npm run demo # and open http://localhost:8080

Contributions welcome!

ng-dynamic's People

Contributors

00muecke avatar lacolaco avatar nud avatar

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    ๐Ÿ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. ๐Ÿ“Š๐Ÿ“ˆ๐ŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google โค๏ธ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.