Angular2: replace host element with component's template

I'm new to angular in general and to angular2 specifically. I'm trying to write a container component, which should have child components in it.

For example, container component:

@Component({
  selector: 'my-list',
  template: `
    <ul>
      <ng-content></ng-content>
    </ul>
  `
})
export class MyList {
}

Child component:

import { Component } from 'angular2/core'

@Component({
  selector: 'my-item',
  template: `
    <li>
      <ng-content></ng-content>
    </li>
  `
})
export class MyItem {
}

I'd like to make this structure:

<my-list>
    <my-item>One</my-item>
    <my-item>Two</my-item>
</my-list>

To be rendered to the following one:

<my-list>
    <ul>
        <li>One</li>
        <li>Two</li>
    </ul>
</my-list>

But instead, I have the host element of the container and the items preserved as well:

<my-list>
    <ul>
        <my-item>
            <li>One</li>
        </my-item>
        <my-item>
            <li>Two</li>
        </my-item>
    </ul>
 </my-list>

Plunk is available here

Question: is there a way to eliminate the host elements and to leave only the rendered template?

Answers


This you should get what you want:

@Component({
  selector: 'ul[my-list]',
  template: `
    <ng-content></ng-content>
  `
})
export class MyList {
}
@Component({
  selector: 'li[my-item]',
  template: `
    <ng-content></ng-content>
  `
})
export class MyItem {
}
<ul my-list>
    <li my-item>One</li my-item>
    <li my-item>Two</li my-item>
</li my-list>

Finally I found solution: injecting ElementRef to MyItem and using its nativeElement.innerHTML:

MyList:

import { Component, ContentChildren, QueryList } from 'angular2/core'
import { MyItem } from './myitem'

@Component({
  selector: 'my-list',
  template: `
    <ul>
      <li *ngFor="#item of items" [innerHTML]="item.innerHTML"></li>
    </ul>
  `
})
export class MyList {
  @ContentChildren(MyItem) items: QueryList<MyItem>
}

MyItem:

import { Directive, Inject, ElementRef } from 'angular2/core'

@Directive({selector: 'my-item'})
export class MyItem {
  constructor(@Inject(ElementRef) element: ElementRef) {
    this.innerHTML = element.nativeElement.innerHTML
  }
}

Working plunk is here


New angular versions have really cool directive, which may be used also for your use case. Tadaa: NgComponentOutlet. Happy coding ;)

Example:

@Component({selector: 'hello-world', template: 'Hello World!'})
class HelloWorld {
}

@Component({
  selector: 'ng-component-outlet-simple-example',
  template: `<ng-container *ngComponentOutlet="HelloWorld"></ng-container>`
})
class NgTemplateOutletSimpleExample {
  // This field is necessary to expose HelloWorld to the template.
  HelloWorld = HelloWorld;
}

There is a hacky workaround solution that may not be supported in older browser versions, but it was working for mine project and I think it is quite easy to integrate without changing or adding a lot of code.

First you need to change selector of MyItem class/component from element selector

selector: 'custom-element-name'

to attribute selector

selector: '[customAttributeName]'

and finally use html slot element to wrap MyItem inside MyList html template

<slot customAttributeName></slot>

Full code:

import { Component } from 'angular2/core'

@Component({
  selector: 'my-list',
  template: `
    <ul>
      <slot myItemAsAtribute></slot>
    </ul>
  `
})
export class MyList {
}


@Component({
  selector: '[myItemAsAtribute]',
  template: `
      <li *ngFor="let item of items">{{item}}</li>

  `
})
export class MyItem {
}

In the latest angular you can even avoid adding <ng-content></ng-content>

I've applied is like:

import {Component} from '@angular/core';

@Component({
    selector: 'div[app-root]',
    templateUrl: 'app.component.html',
    styleUrls: ['app.component.css']
})
export class AppComponent {
    title = 'Delegates Presence Reporting';
}

and the template:

<div class="centered">
<h1>{{title}}</h1>
</div>

index.html

<body>
<div app-root></div>
</body>

Need Your Help

Using Url.Content with semi-relative URL

asp.net-mvc razor

I am storing the location of images in my database in an MVC application...but i am only storing part of the location. For example:

How to use Maven in my Java Project and Why?

java maven-2

I am trying to figure out the use of Maven and I got many articles describing its features and uses. But I am just not able to understand the actual use of Maven from productivity standpoint.