2

Let's say I have this Component :

import { Component, OnInit, AfterViewInit, ViewChild, ElementRef, ViewEncapsulation } from '@angular/core';
import { Http, Response } from '@angular/http';
import { ActivatedRoute, Params } from '@angular/router';
import 'rxjs/add/operator/toPromise';

@Component({
  selector: 'jlm-chapitre',
  templateUrl: './chapitre.component.html',
  styleUrls: ['./chapitre.component.scss'],
  encapsulation: ViewEncapsulation.None
})
export class ChapitreComponent implements OnInit, AfterViewInit {
  @ViewChild('include', { read: ElementRef }) includeDiv: ElementRef;

  constructor( private route : ActivatedRoute, private http: Http ) { }

  ngAfterViewInit() {
    this.route.params.forEach((params: Params) => {
      let id = +params['chapitreId'];
      this.http.get(`/assets/programme/chapitre0${id}.html`)
      .toPromise()
      .then((res: Response) => {
        this.includeDiv.nativeElement.innerHTML = res.text();
      });
    });
  }

  ngOnInit() {}
}

But the problem here is that the inserted HTML content is not compiled.

I have an undetermined number of html templates, so I can't create one component per html template... How to insert AND compile the template ? We had $compile() in angular1. We had DynamicComponentLoader but it's been deprecated...

edit : After reading first answers, it looks like I wasn't clear enough. I want to load a raw HTML template from the server, with directives etc in it and I want those directives to be evaluated when I insert the template within (or after) the #includeDiv. It looks like the Renderer might do the job but I do not know how to use renderer.insertViewAfter(). Anyway, whatever fixes the problem would make me very happy.

edit 2 : I found an easy way of doing what I just said in the answer to another question : https://stackoverflow.com/a/39773331/3444388

But I'm still looking for something a bit cleaner.

Community
  • 1
  • 1
iuliust
  • 278
  • 1
  • 10
  • So you're trying to get raw html back from the server and then display it in your angular 2 template? – Kevin Aud Oct 16 '16 at 04:54
  • it's not really clear why you are trying to do this this way. You *appear* to want to store angular templates on your server in some format other than a template, possibly in a database or something else. It's generally against MVC principles to have a server generate a view, and it's usually not a good idea to store a template in your database, since it's not data. (unless the templates are user created, and then that's a completely different can of worms). – Claies Oct 16 '16 at 16:51
  • No, the templates are not user created (I'm not crazy !). The templates were all created by me. But I like flexibility. If you want to take a look at it, here's the link : https://github.com/iuliust/jlm The idea is the following : in France, the presidential elections will take place in a few months. I put the program of my favorite candidate on gitHub in the form of HTML documents. The rendering of the templates will be dynamic. And I would love people to fork the HTML templates submodule, and do whatever changes they want. Then they could make pull requests... – iuliust Oct 17 '16 at 18:10

2 Answers2

0

I notice that the only thing that changes is the chapter ID. Assuming that the HTML from one chapter to the next has the same basic structure with different content, you could use a common template:

<section *ngIf="ready">
    <h2>{{chapter.title}}</h2>
    <div>{{chapter.description}}</div>
</section>
<section *ngIf="!ready">Loading chapter...</section>

Then in the component, you sead ready=false by default. In ngOnInit, fetch the chapter information. Once it arrives set it to a local variable and make ready=true to display the template

chapter;
ready = false;
ngOninit() {
    ...
    let id = +params['chapitreId'];
    this.http.get('...').subscribe(
        data => {
            this.chapter = data;
            this.ready = true;
        }
    )
}

Better yet, you could use a Resolve guard to fetch the data before your component even loads.

BeetleJuice
  • 39,516
  • 19
  • 105
  • 165
0

I don't really understand why you want to override the content on every single http response but if you want to display a list, just use ngFor.

If you want to not display the content before it's loaded, just use the safe navigation operator <p>{{text?}}</p>.

export class ChapitreComponent implements OnInit, AfterViewInit {
   ...
   text: String;

   ...
      .then(res: Response) => {
         this.text = res.text
      }
   ...
}


<p>{{text?}}</p>

If you want to override the content in your code, Angular 2 has a very awesome renderer for you!

renderer.setText(this.includeDiv.nativeElement, res.text);

https://angular.io/docs/ts/latest/api/core/index/Renderer-class.html

Clite Tailor
  • 438
  • 5
  • 14
  • Thank you for your answer. But the problem is that the html template I fetched is not compiled. For instance, if there's an *ngIf="false" directive, it's not evaluated. The text is sanitized. Furthermore, it's an HTML template, which means that there are tags within tags within tags. With directives attached to them. Putting {{text}} in the component's template won't be enough. – iuliust Oct 16 '16 at 15:28
  • oh, sorry i didn't see the question you ask below! – Clite Tailor Oct 16 '16 at 17:12