Ответ 1
Вы можете использовать селектор атрибутов
@Component({
selector: '[myTd]'
...
})
а затем используйте его как
<td myTd></td>
Я изо всех сил пытаюсь найти способ сделать это. В родительском компоненте шаблон описывает элемент table
и его thead
, но делегирует отображение tbody
другому компоненту, например:
<table>
<thead>
<tr>
<th>Name</th>
<th>Time</th>
</tr>
</thead>
<tbody *ngFor="let entry of getEntries()">
<my-result [entry]="entry"></my-result>
</tbody>
</table>
Каждый компонент myResult отображает собственный тег tr
, в основном так:
<tr>
<td>{{ entry.name }}</td>
<td>{{ entry.time }}</td>
</tr>
Причина, по которой я не помещаю это прямо в родительский компонент (исключая необходимость в компоненте myResult), заключается в том, что компонент myResult на самом деле более сложный, чем показано здесь, поэтому я хочу поместить его поведение в отдельный компонент и файл.
В результате DOM выглядит плохо. Я считаю, что это неверно, поскольку tbody
может содержать только tr
элементы (см. MDN), но мои сгенерированные (упрощенные) DOM:
<table>
<thead>
<tr>
<th>Name</th>
<th>Time</th>
</tr>
</thead>
<tbody>
<my-result>
<tr>
<td>Bob</td>
<td>128</td>
</tr>
</my-result>
</tbody>
<tbody>
<my-result>
<tr>
<td>Lisa</td>
<td>333</td>
</tr>
</my-result>
</tbody>
</table>
Есть ли способ получить то же самое, что и рендеринг, но без тэга wrapping <my-result>
, и все еще используя компонент, который должен отвечать за визуализацию строки таблицы?
Я просмотрел ng-content
, DynamicComponentLoader
, ViewContainerRef
, но они, похоже, не дают решения для этого, насколько я могу видеть.
Вы можете использовать селектор атрибутов
@Component({
selector: '[myTd]'
...
})
а затем используйте его как
<td myTd></td>
Используйте эту директиву на вашем элементе
@Directive({
selector: '[remove-wrapper]'
})
export class RemoveWrapperDirective {
constructor(private el: ElementRef) {
const parentElement = el.nativeElement.parentElement;
const element = el.nativeElement;
parentElement.removeChild(element);
parentElement.parentNode.insertBefore(element, parentElement.nextSibling);
parentElement.parentNode.removeChild(parentElement);
}
}
Пример использования:
<div class="card" remove-wrapper>
This is my card component
</div>
и в родительском html вы вызываете элемент карты как обычно, например:
<div class="cards-container">
<card></card>
</div>
Выход будет:
<div class="cards-container">
<div class="card" remove-wrapper>
This is my card component
</div>
</div>
Вам нужно "ViewContainerRef" и внутри компонента my-result сделать что-то вроде этого:
HTML:
<ng-template #template>
<tr>
<td>Lisa</td>
<td>333</td>
</tr>
</ng-template>
TS:
@ViewChild('template') template;
constructor(
private viewContainerRef: ViewContainerRef
) { }
ngOnInit() {
this.viewContainerRef.createEmbeddedView(this.template);
}
Ни один из предложенных ответов не работает или не является полным. Правильный ответ описан здесь с примером плунжера. Удалите тег компонента узла из HTML в угловых 4
Селекторы атрибутов - лучший способ решить эту проблему.
Итак, в вашем случае:
<table>
<thead>
<tr>
<th>Name</th>
<th>Time</th>
</tr>
</thead>
<tbody my-results>
</tbody>
</table>
my-results ts
import { Component, OnInit } from '@angular/core';
@Component({
selector: 'my-results, [my-results]',
templateUrl: './my-results.component.html',
styleUrls: ['./my-results.component.css']
})
export class MyResultsComponent implements OnInit {
const entries = [
{ name: 'Entry One', time: '10:00'},
{ name: 'Entry Two', time: '10:05 '},
{ name: 'Entry Three', time: '10:10'},
];
constructor() { }
ngOnInit() {
}
}
html my-results
<tr my-result [entry]="entry" *ngFor="let entry of entries"><tr>
my-result ts
import { Component, OnInit, Input } from '@angular/core';
@Component({
selector: '[my-result]',
templateUrl: './my-result.component.html',
styleUrls: ['./my-result.component.css']
})
export class MyResultComponent implements OnInit {
@Input() entry: any;
constructor() { }
ngOnInit() {
}
}
html my-result
<td>{{ entry.name }}</td>
<td>{{ entry.time }}</td>
Смотрите рабочий стек: https://stackblitz.com/edit/angular-xbbegx
Помимо выбранного ответа выше, вы также можете использовать ng-template или ng-container