Dynamic template in templatURL in angular2

2020-01-27 04:58发布

问题:

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...

回答1:

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.



回答2:

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.



回答3:

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 templateUrlto 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.



回答4:

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>


回答5:

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>