16

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

binariedMe
  • 4,309
  • 1
  • 18
  • 34
  • try this http://stackoverflow.com/questions/34457716/dynamic-template-transclusion-in-angular2 or http://stackoverflow.com/questions/33034930/how-to-use-angular2-dynamiccomponentloader-in-es6 or https://angular.io/docs/ts/latest/api/core/DynamicComponentLoader-class.html – Gary Mar 06 '16 at 10:00

5 Answers5

11

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.

S.Klechkovski
  • 4,005
  • 16
  • 27
  • 1
    Is it possible to set input parameters on the dynamically created component? I am trying to convert an angular 1 grid to angular 2. the original had custom cell templates. I implemented the above but can't get any binding to work – Jason Jun 23 '16 at 12:24
  • I need my existing class instead of 'MyNgIncludeContent' class. Class name comes in the same way as url comes. Is it possible? – Parshwa Shah Oct 18 '16 at 07:18
  • 1
    @Jason did you find the solution.? I am also looking for the same. How to compile the child element (html template) with data for all the cells in specific column(template column might be grid-template directive).? – Karthick Oct 18 '16 at 10:58
  • @Karthick, yes you can pass data to the template, I have modified the plunker for that (http://plnkr.co/edit/JffJ5ifgeIyIPWZORwyA?p=preview). Please ping me if this is what you were looking for. However this is an old example back from the rc1 release and I haven't check if this still works with the final version. – S.Klechkovski Oct 21 '16 at 16:50
  • @S.Klechkovski yes, something near to the solution. Is this possible to create the ViewChild with dynamic input of the method. @ViewChild(dynamicPlaceHolder) – Karthick Oct 21 '16 at 17:17
3

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.

binariedMe
  • 4,309
  • 1
  • 18
  • 34
  • yeah that is also possible and better. Thanks for the suggestion. Actually by "A piece of javascript " I meant the same. – binariedMe Feb 17 '16 at 10:35
1

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.

sdnyco
  • 13
  • 3
  • Thats not the question I asked... I know how to add template... All I want is only one component importing different template as per requirement. This was possible in angular 1 using ng-include. – binariedMe Nov 18 '15 at 04:10
  • Then the simple answer is **no**. As your own research shows the Angular team removed ngInclude by design. [It is no longer possible to implement ng-include. The compiler requires a ComponentDirective in order to compile HTML. Therefor you cannot compile HTML on its own and include it into a View.](http://eisenbergeffect.bluespire.com/all-about-angular-2-0/) – sdnyco Nov 18 '15 at 10:36
  • 1
    Not off the top of my head. I have scoured the official [Angular repo](https://github.com/angular/angular/issues) to find approaches on how to dynamically import templates... to no avail so far. I'll make sure to update once I know more. – sdnyco Nov 18 '15 at 15:50
1

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>
Wtower
  • 18,848
  • 11
  • 103
  • 80
0

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>
thejava
  • 108
  • 2
  • 10