martin
martin

Reputation: 96891

Component with <ng-content>

I've seen working examples when <ng-content> is beeing used inside other nested components (like here) but I haven't managed to run it inside a root Angular2 component:

HTML template:

<html>
    <body>
        <app>
            <h1>Hello, World!</h1>
        </app>
    </body> 
</html>

Angular 2 component in TypeScript:

import {Component, View, bootstrap} from 'angular2/angular2';

@Component({
    selector: 'app'
})
@View({
    template: 'Header: <ng-content></ng-content>',
})
export class App {
}

bootstrap(App);

I'd expect that this will generate:

<app>
    Header: <h1>Hello, World!</h1>
</app>

but it doesn't and the content of <app> is ignored. See demo on Plunker.

I thought maybe this goes against some Angular 2 philosophy or something so it's not even supported, but my use case is very similar to the first working demo I think.

Upvotes: 22

Views: 19657

Answers (2)

Jesse Good
Jesse Good

Reputation: 52365

When you run your example, did you notice how Hello World! is displayed during loading?

Basically, the HTML between <app> and </app> is used to display something while Angular is booting up.

Also, from the source:

An application is bootstrapped inside an existing browser DOM, typically index.html. Unlike Angular 1, Angular 2 does not compile/process bindings in index.html. This is mainly for security reasons, as well as architectural changes in Angular 2. This means that index.html can safely be processed using server-side technologies such as bindings. Bindings can thus use double-curly {{ syntax }} without collision from Angular 2 component double-curly {{ syntax }}.

The important part being Angular 2 does not compile/process bindings in index.html. So, in order to do what you want, you will have to move ng-content to a child component.

Upvotes: 26

Andr&#233; Werlang
Andr&#233; Werlang

Reputation: 5944

Turns out it's possible, if you intend to provide textual content. If you want Angular components, it's possible with the right HTML element (noscript). A little hacky, one might say. The trick is using a <noscript> element.

HTML template:

<noscript id="appContent">
   <h1>Hello, World!</h1>
   <a [routerLink]="['Home']">Home</a>
</noscript>
<script>
    var mainTemplate = document.getElementById('appContent');
    window.mainTemplate = mainTemplate.innerText;
</script>

Root component:

import {Component, bootstrap} from 'angular2/angular2';

@Component({
    selector: 'app',
    template: 'Header: ' + window.mainTemplate ,
})
export class App {
}

bootstrap(App);

Make sure your Angular 2 code comes after the template definition.

Only applies if you use a <template> tag: The catch is that since recently (http://angularjs.blogspot.com.br/2016/02/angular-2-templates-will-it-parse.html) Angular 2 brings its own parser, templates are case-sensitive. It is not the case for HTML in a browser environment. It means the browser may not keep the case in attributes and elements on this template hack.

UPDATE: I had a <template> element in the original solution. A <noscript> is much better as shouldn't be any case conversion.

Upvotes: 13

Related Questions