Angular2 : 래핑 태그없이 컴포넌트 렌더링


100

나는 이것을 할 방법을 찾기 위해 고군분투하고 있습니다. 상위 구성 요소에서 템플릿은 a 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만 포함 할 수 있기 때문에 (MDN 참조) 유효하지 않기 때문이라고 생각 하지만 생성 된 (단순화 된) DOM은 다음과 같습니다.tr

<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>

동일한 것을 렌더링 할 수 있지만 래핑 <my-result>태그 없이 구성 요소를 사용하여 테이블 행 렌더링을 단독으로 수행 할 수있는 방법이 있습니까?

내가 살펴 보았다 ng-content, DynamicComponentLoaderViewContainerRef,하지만 그들은 지금까지 내가 볼 수있는이에 대한 해결책을 제공하지 않는 것.


실제 사례를 보여 주시겠습니까?
zakaria amine

2
정답이 있습니다. 플 런커 샘플 stackoverflow.com/questions/46671235/…
sancelot

1
제안 된 답변이 작동하지 않거나 완전하지 않습니다. 정답은 여기에 플 런커 샘플로 설명되어 있습니다. stackoverflow.com/questions/46671235/…
sancelot

답변:


95

속성 선택기를 사용할 수 있습니다.

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

다음과 같이 사용하십시오.

<td myTd></td>

구성 요소의 선택기에 []? declarations: [...]모듈에 구성 요소를 추가 했습니까 ? 컴포넌트가 다른 모듈에 등록 된 경우 해당 컴포넌트 imports: [...]를 사용하려는 모듈 에이 다른 모듈을 추가 했 습니까?
Günter Zöchbauer

1
아니 setAttribute내 코드가 아닙니다. 그러나 나는 그것을 알아 냈어요, 내가 대신 내 구성 요소의 태그로 내 템플릿에 실제 최상위 태그를 사용하는 데 필요한 ng-container때문에 새로운 작업 사용법입니다<ul smMenu class="nav navbar-nav" [submenus]="root?.Submenus" [title]="root?.Title"></ul>
Aviad P.

1
DOM에서 제거되었으므로 ng-container에 속성 구성 요소를 설정할 수 없습니다. 이것이 실제 HTML 태그에 설정해야하는 이유입니다.
Robouste 2017

2
@AviadP. 고마워요 ... 사소한 변화가 필요하다는 걸 알았고 이것 때문에 정신이 나갔어요. 그래서 이것 대신 : <ul class="nav navbar-nav"> <li-navigation [navItems]="menuItems"></li-navigation> </ul>나는 이것을 사용했습니다 (속성 선택 자로 li-navigation을 변경 한 후)<ul class="nav navbar-nav" li-navigation [navItems]="menuItems"></ul>
Mahesh

3
이 대답은 재료 구성 요소를 보강하려는 경우 작동하지 않습니다. 예를 들어 <mat-toolbar my-toolbar-rows>는 구성 요소 선택기를 여러 개가 아니라 하나만 가질 수 있다고 불평합니다. 나는 <my-toolbar-component>로 갈 수 있지만 div 안에 mat-toolbar를 넣습니다
robert king

20

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

3
매력처럼 작동합니다! 감사합니다. 대신 Angular 8에서 다음을 사용했습니다.@ViewChild('template', {static: true}) template;
AlainD.

1
이것은 효과가 있었다. 나는 css display : grid를 사용하는 상황이 있었고 my-result의 모든 하위 요소가 my-result의 형제로 렌더링되는 부모의 첫 번째 요소로 여전히 <my-result> 태그를 가질 수 없습니다. . 문제는 하나의 추가 고스트 요소가 여전히 그리드 7 개 열 "grid-template-columns : repeat (7, 1fr);"을 깨뜨렸다는 것입니다. 8 개의 요소를 렌더링했습니다. my-result에 대한 고스트 자리 표시 자 1 개와 열 헤더 7 개. 이에 대한 해결 방법은 태그에 <my-result style = "display : none">을 넣어 단순히 숨기는 것입니다. CSS 그리드 시스템은 그 후 매력처럼 작동했습니다.
Randall2

이 솔루션은 my-resultmy-result형제 를 만들 수 있어야 하는 더 복잡한 경우에도 작동합니다 . 따라서 my-result각 행에 "하위"행이있을 수 있는 계층이 있다고 가정합니다 . 이 경우 첫 번째 선택기가으로 이동하기 때문에 속성 선택기를 사용하면 작동하지 tbody않지만 두 번째 선택기는 내부 tbody또는 tr.
Daniel

1
이것을 사용할 때 어떻게 ExpressionChangedAfterItHasBeenCheckedError를 피할 수 있습니까?
gyozo kudor

@gyozokudor 아마도 setTimeout 사용
Diego Fernando Murillo Valenci

12

요소에이 지시문 사용

@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>

6
'parentElement.parentNode'가 null이기 때문에 오류가 발생합니다
emirhosseini

아이디어는 좋지만 제대로 작동하지 않습니다 :-(
jpmottin

9

속성 선택기는이 문제를 해결하는 가장 좋은 방법입니다.

따라서 귀하의 경우 :

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

내 결과 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() {
  }

}

내 결과 html

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

내 결과 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

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

작업 stackblitz 참조 : https://stackblitz.com/edit/angular-xbbegx


selector : 'my-results, [my-results]', 그런 다음 HTML의 태그 속성으로 my-results를 사용할 수 있습니다. 이것이 정답입니다. Angular 8.2에서 작동합니다.
Don Dilanga

8

새로운 CSS를 사용해 볼 수 있습니다. display: contents

내 툴바 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;
}

및 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>

그리고 사용 중 :

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

3

요즘 또 다른 옵션 ContribNgHostModule@angular-contrib/common패키지 에서 제공되는 것 입니다.

모듈을 가져온 후 당신은 추가 할 수 있습니다 host: { ngNoHost: '' }당신을 @Component장식하고 더 포장 요소는 렌더링되지 않습니다.

당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.