Basit
Basit

Reputation: 17184

Angular2 component - render html from the index page

Is it possible to render html which is inside app-nav tag already, rather then providing it in templateUrl?

@Component({
  selector: 'app-nav',
  // commented out - templateUrl: './nav.component.html',
  styleUrls: ['./nav.component.scss']
})
export class NavComponent {
  title: string = 'This is my title';
}

Html that is already on the html page.

<app-nav>
  nav works! {{ title }}
</app-nav>

If I uncomment the templateUrl then app-nav will be replaced by nav-component.html page, but I dont want that. I have dynamic html and I want to render that.

Upvotes: 3

Views: 1333

Answers (2)

Richard Matsen
Richard Matsen

Reputation: 23463

@Yaroslav, expanding on your solution:

  1. Looks like a transclusion (in Angular 1 terms), so in Angular 2 you can use ng-content on the inner component.

    <div class="my-component">
      <ng-content></ng-content>
    </div>
    
  2. To get interpolation working on outer transcluded markup, give the element an id and prefix the interpolated content with it.

    <my-component #comp>
      This is my transcluded content! ++{{comp.title}}++
    </my-component>
    
  3. Don't try to transclude from index.html, it's not an angular component, so it doesn't seem to work as the outer component. If you use app.component as the outer and another my.component as inner, it works.

Here's a fork of your plunkr with the changes. plnkr

For reference, I used Todd Motto's excellent article on angular 2 transclusion: ref here.
The angular guide only vaguely refers to ng-content (with a link that 404's), so I wonder if it's disappearing. May be superseded by ngComponentOutlet ref here

Upvotes: 0

Yaroslav Grishajev
Yaroslav Grishajev

Reputation: 2137

You can use embedded view with ngTemplateOutlet projection. Wrap your content within <app-nav> tags in <template>. Than in your NavComponent find this TemplateRef with ContentChild and insert this templateRef into component's template passing context that contains your title variable to it. Something like this:

@Component({
  selector: 'app-nav',
  templateUrl: './nav.component.html',
  styleUrls: ['./nav.component.scss']
})
export class NavComponent {
  title: string = 'This is my title';

  @ContentChild('defaultTemplate') defaultTemplate = null // get templateRef
}

In nav.component.html create template outlet with relative template context

<template [ngOutletContext]="{ title: title }" [ngTemplateOutlet]="defaultTemplate"></template>

....other component content....

And then in place of component use:

<app-nav>
  <template #defaultTemplate let-title="title">
    nav works! {{ title }}
  </template>
</app-nav>

UPD:

Here is a plunk with example

in app/some.component.ts there is a ngTemplateOutlet projection from app/app.component.ts template

UPD:

Ok, there is a way to get initial content from index.html into the component. You can use APP_INITIALIZER function that will be executed when an application is initialized.

Here is the plunk

  1. See app/root-template.initializer.ts
  2. In app/app.component.ts I just replace relevant property with initial content. This is a bit hacky way and should be done by replacing template in ComponentMetadata which is obtained with Reflect.getMetadata:

    const annotations = Reflect.getMetadata('annotations', NavComponent)
    const meta = annotations.find(annotation => annotation instanceof ComponentMetadata)
    
    meta.template = meta.template.replace(
      '{{ someVarInTemplate }}',
      'initialContentInIndex'
    )
    

This way the component template will have initial index content and it will be parsed by angular. More about Reflect here

Upvotes: 2

Related Questions