Read HTML File into template in Angular 2?

19,097

Solution 1

What you need here is something like ng-include I suppose. 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.

Solution 2

It may be maligned as "verboten" for a number of reasons that I understand, including the underscore you will see, but this works. Fact is I have a need to do this very simply and I don't want to (nor should I have to) write a lot of code to do it. I can scrub the HTML etc. I get if this is more helpful than an answer but some may find it useful.

In the component API (ES6 style), declare a queries entry (or otherwise create your ViewChild using TS), this should map to an element with a template reference variable and so on. Note that using the queries part of the component API as I show here works fine in TS:

  // Assumes you have <div #targetdiv></div> in your component template
  queries: {
    targetDivRef : new ViewChild ( 'targetdiv' )
  }

Then in some click handler, onInit or whatever (keeping in mind not to try this too early in the comp lifecycle) get the page you want async, and just dump the contents into the div.

   let elem = this.targetDivRef.nativeElement;

   let svc = this.http.get ( './thepage.html' )
      .map ( response => { return response [ '_body' ] } );

   svc.subscribe (
      ( x ) => { elem.innerHTML = x },
      ( err ) => console.log ( err ),
      ( ) => console.log ( 'Complete' )
    )

Again, almost surely not "recommended". But it's simple and it works. You actually don't even need the subscribe, you can just set the val in the map func, this is just more complete etc.

When we get an option similar to ng-include (which IMHO is a glaring ommission), or an otherwise three-line option to do this, I'll make the switch. Handle request errors etc. as you see fit.

Share:
19,097

Related videos on Youtube

EMChamp
Author by

EMChamp

Updated on September 14, 2022

Comments

  • EMChamp
    EMChamp over 1 year

    I'm trying to create dynamic modals in Angular 2 using the ng2-bs3-modals. I would like to fill in the modal html body text dynamically based on the parameter passed to the selector used in the main component's view. When I use this code however it seems to treat my entire function as text and so my modal displays the code of my 'function determineModalContent' rather than the intended behavior which is to display the contents of the file.

    I also know that my code won't return the contents of the file, just the string but I haven't yet figured out how in Angular2/TypeScript to read in the file contents.

    import { Component, Input } from 'angular2/core'
    
    @Component({
        selector: 'static-modal',
        template: '{{modalBody}}'
    })
    
    
    export class StaticModalComponent {
        @Input() modalID;
        template = 'app/shared/modals/static-message-1.html'
        modalBody = function determineModalContent(modalID){
                if(modalID == "1")
                    return 'app/shared/modals/static-message-1.html';
                else if(modalID == "2")
                    return 'app/shared/modals/static-message-2.html';
                else   
                    return 'app/shared/modals/static-message-default.html';
        }
    }
    
  • JSNinja
    JSNinja over 7 years
    Thanks for the example, but the ComponentResolver is no more the part of angular/core package. Is there a work around for this?
  • Nrzonline
    Nrzonline over 6 years
    And what if you need to implement the modals on multiple pages? You need to copy-past it in every page. And what if you need to modify a few lines of that code? You will need to modify it in all the pages where it got implemented... Not really dry
  • Maxime Bouveron
    Maxime Bouveron over 6 years
    @Nrzonline Didn't work with Angular since this answer, but you can extract that code in a different component, no?