简体   繁体   中英

Dynamic template in templatURL in angular2

I have been using ng-include in angular 1 whenever I had to include a tamplate dynamically in the page.

Now how to acheive this in angular 2. I have tried searching and found these :

https://groups.google.com/forum/#!topic/angular/ROkKDHboWoA ,

https://github.com/angular/angular/issues/2753

can someone explain how to do this in angular2 as the link says ng-include is not included due some security reasons.

Or atleast how to use a veriable in templateUrl property so that the veriable value can be handled on server side to serve the template...

And as you can see in this issue on the Angular repo, most probably we won't get that directive. There has been a long discussion whether we need this directive or not, and if not provided how we can implement it by our self.

I tried to make a simple example of how it can be implemented.

@Component({
    selector: 'my-ng-include',
    template: '<div #myNgIncludeContent></div>'
})
export class MyNgInclude implements OnInit {

    @Input('src')
    private templateUrl: string;

    @ViewChild('myNgIncludeContent', { read: ViewContainerRef })
    protected contentTarget: ViewContainerRef;

    constructor(private componentResolver: ComponentResolver) {}

    ngOnInit() {
        var dynamicComponent = this.createContentComponent(this.templateUrl);
        this.componentResolver.resolveComponent(dynamicComponent)
            .then((factory: any) => this.contentTarget.createComponent(factory));
    }

    createContentComponent(templateUrl) {
        @Component({
            selector: 'my-ng-include-content',
            templateUrl: templateUrl,
            directives: FORM_DIRECTIVES,
        })
        class MyNgIncludeContent {}
        return MyNgIncludeContent ;
    }
}

For a demo check this Plunker .

Actually angular 2 has not featured this in the current build. Also as per the links added, I don't think this feature will be included.

A piece of javascript to dynamically add template using ajax call may be used.

Or possibly in future a dynamic template loader library will be available for use.

As of alpha.46 (and with ES6 JS):

In the parent file import file you wanted to include:

@Component({
  selector: 'account'
})
@View({
  templateUrl: './folder/containing/template.html'
})

Easy as that.

If you meant to import a component, this is what you do in the parent file:

import ComponentClassName from './folder/with/componentName';

...

@View({
  directives: [ComponentClassName]
})

And inside the imported file of the child /component:

Define your ComponentClassName (you may add templateUrl to the @View just as demonstrated at the top).

Don't forget to export default ComponentClassName; at the bottom of the file.

There are not many examples in the official Angular 2 docs, but you stumble across it every once in a while .

As @binariedMe accurately describes, ng-include is off in Angular 2 due to security considerations. The recommended method is to use a custom directive with slightly more programmatical overhead.

Additionally, to prepare your Angular code for 2.0:

myApp.directive('myInclude', function() {
    return {
        templateUrl: 'mytemplate.html'
    };
});

And rather than using ng-include on an element, simply add my-include :

<div my-include></div>

Following @binariedMe and this blog post http://blog.lacolaco.net/post/dynamic-component-creation-in-angular-2/ , I was able to construct a solution that may work for you. Using an AJAX call and creating the custom component dynamically from the returned html content should fix this problem in creating a new my-ng-include custom directive.

import {
  Component,
  Directive,
  ComponentFactory,
  ComponentMetadata,
  ComponentResolver,
  Input,
  ReflectiveInjector,
  ViewContainerRef
} from '@angular/core';
import { Http } from '@angular/http';

export function createComponentFactory(resolver: ComponentResolver, metadata: ComponentMetadata): Promise<ComponentFactory<any>> {
    const cmpClass = class DynamicComponent {};
    const decoratedCmp = Component(metadata)(cmpClass);
    return resolver.resolveComponent(decoratedCmp);
}

@Directive({
    selector: 'my-ng-include'
})
export class MyNgInclude {

    @Input() src: string;

    constructor(private vcRef: ViewContainerRef, private resolver: ComponentResolver, private http: Http) {
    }

    ngOnChanges() {
      if (!this.src) return;

      this.http.get(this.src).toPromise().then((res) => {
        const metadata = new ComponentMetadata({
            selector: 'dynamic-html',
            template: res.text(),
        });
        createComponentFactory(this.resolver, metadata)
          .then(factory => {
            const injector = ReflectiveInjector.fromResolvedProviders([], this.vcRef.parentInjector);
            this.vcRef.createComponent(factory, 0, injector, []);
          });
      });
    }
}

Just simply use it as follows:

<my-ng-include [src]="someChangingProperty"></my-ng-include>

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM