Javascript Angular2:渲染一个没有包装标签的组件

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/38716105/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-23 21:45:35  来源:igfitidea点击:

Angular2 : render a component without its wrapping tag

javascriptangular

提问by Greg

I am struggling to find a way to do this. In a parent component, the template describes a tableand its theadelement, but delegates rendering the tbodyto another component, like this:

我正在努力寻找一种方法来做到这一点。在父组件中,模板描述 atable及其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>

Each myResult component renders its own trtag, basically like so:

每个 myResult 组件呈现自己的tr标签,基本上是这样的:

<tr>
  <td>{{ entry.name }}</td>
  <td>{{ entry.time }}</td>
</tr>

The reason I'm not putting this directly in the parent component (avoiding the need for a myResult component) is that the myResult component is actually more complicated than shown here, so I want to put its behaviour in a separate component and file.

我没有将它直接放在父组件中(避免需要 myResult 组件)的原因是 myResult 组件实际上比这里显示的更复杂,所以我想把它的行为放在单独的组件和文件中。

The resulting DOM looks bad. I believe this is because it is invalid, as tbodycan only contain trelements (see MDN), but my generated (simplified) DOM is :

生成的 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>

Is there any way we can get the same thing rendered, but without the wrapping <my-result>tag, and while still using a component to be sole responsible for rendering a table row ?

有没有什么办法可以让我们渲染同样的东西,但没有包装<my-result>标签,同时仍然使用一个组件来单独负责渲染表格行?

I have looked at ng-content, DynamicComponentLoader, the ViewContainerRef, but they don't seem to provide a solution to this as far as I can see.

我已经看过ng-content, DynamicComponentLoader, the ViewContainerRef,但据我所知,他们似乎没有提供解决方案。

采纳答案by Günter Z?chbauer

You can use attribute selectors

您可以使用属性选择器

@Component({
  selector: '[myTd]'
  ...
})

and then use it like

然后像这样使用它

<td myTd></td>

回答by Slim

You need "ViewContainerRef" and inside my-result component do something like this:

您需要“ViewContainerRef”并在 my-result 组件中执行以下操作:

html:

html:

<ng-template #template>
    <tr>
       <td>Lisa</td>
       <td>333</td>
    </tr>
 </ng-template>

ts:

ts:

@ViewChild('template') template;


  constructor(
    private viewContainerRef: ViewContainerRef
  ) { }

  ngOnInit() {
    this.viewContainerRef.createEmbeddedView(this.template);
  }

回答by Shlomi Aharoni

Use this directive on your element

在您的元素上使用此指令

@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);
   }
}

Example usage:

用法示例:

<div class="card" remove-wrapper>
   This is my card component
</div>

and in the parent html you call card element as usual, for example:

在父 html 中,您像往常一样调用 card 元素,例如:

<div class="cards-container">
   <card></card>
</div>

The output will be:

输出将是:

<div class="cards-container">
   <div class="card" remove-wrapper>
      This is my card component
   </div>
</div>

回答by Nicholas Murray

Attribute selectors are the best way to solve this issue.

属性选择器是解决这个问题的最好方法。

So in your case:

所以在你的情况下:

<table>
  <thead>
    <tr>
      <th>Name</th>
      <th>Time</th>
    </tr>
  </thead>
  <tbody my-results>
  </tbody>
</table>

my-results ts

我的结果 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 {

  entries: Array<any> = [
    { name: 'Entry One', time: '10:00'},
    { name: 'Entry Two', time: '10:05 '},
    { name: 'Entry Three', time: '10:10'},
  ];

  constructor() { }

  ngOnInit() {
  }

}

my-results html

我的结果 html

  <tr my-result [entry]="entry" *ngFor="let entry of entries"><tr>

my-result ts

我的结果 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() {
  }

}

my-result html

我的结果 html

  <td>{{ entry.name }}</td>
  <td>{{ entry.time }}</td>

See working stackblitz: https://stackblitz.com/edit/angular-xbbegx

查看工作堆栈闪电战:https://stackblitz.com/edit/angular-xbbegx

回答by robert king

you can try use the new css display: contents

你可以尝试使用新的 css display: contents

here's my toolbar scss:

这是我的工具栏 scss:

:host {
  display: contents;
}

:host-context(.is-mobile) .toolbar {
  position: fixed;
  /* Make sure the toolbar will stay on top of the content as it scrolls past. */
  z-index: 2;
}

h1.app-name {
  margin-left: 8px;
}

and the html:

和 html:

<mat-toolbar color="primary" class="toolbar">
  <button mat-icon-button (click)="toggle.emit()">
    <mat-icon>menu</mat-icon>
  </button>
  <img src="/assets/icons/favicon.png">
  <h1 class="app-name">@robertking Dashboard</h1>
</mat-toolbar>

and in use:

并在使用中:

<navigation-toolbar (toggle)="snav.toggle()"></navigation-toolbar>

回答by mjswensen

Another option nowadays is the ContribNgHostModulemade available from the @angular-contrib/commonpackage.

现在的另一种选择是ContribNgHostModule@angular-contrib/common包中提供

After importing the module you can add host: { ngNoHost: '' }to your @Componentdecorator and no wrapping element will be rendered.

导入模块后,您可以添加host: { ngNoHost: '' }@Component装饰器中,并且不会呈现任何包装元素。