Создать повторяемый угловой компонент с двумя строками для таблиц - PullRequest
3 голосов
/ 21 июня 2019

У меня есть два компонента. Первый представляет таблицу элементов, а второй представляет один элемент. Первый повторяет второй много раз.

Компонент списка (app-list):

<table>
    <tr *ngFor="let item of items" [item]="item" app-item></tr>    
</table>

Компонент изделия (app-item):

<td>
    <img src="https://someimage.com/{{item.img}}.jpg">
</td>
<td>
    <h3>{{item.name}}</h3>
</td>
<td>
    {{item.description}}
</td>

Чтобы это работало, мне пришлось использовать селектор атрибута для компонента app-item:

@Component({
  selector: '[app-item]'
})

Это прекрасно работает.


Теперь я хочу улучшить его и добавить второй ряд в каждый app-item. Моя проблема в том, что тег tr лежит в компоненте app-list вместо компонента app-item. Я думал, что если я переместу его в компонент app-item, я мог бы добавить еще tr и иметь возможность показывать две строки на один элемент. Так вот что я сделал. После этого я использовал ng-container, чтобы повторить элементы в моем app-list, чтобы избежать добавления тега-обертки вокруг моих двух строк:

<ng-container *ngFor="let item of items" [item]="item" app-item></ng-container>

Это решение не сработало. Я получил следующую ошибку:

ERROR TypeError: el.setAttribute is not a function
    at EmulatedEncapsulationDomRenderer2.push../node_modules/@angular/platform-browser/fesm5/platform-browser.js.DefaultDomRenderer2.setAttribute (platform-browser.js:1089)
    at EmulatedEncapsulationDomRenderer2.push../node_modules/@angular/platform-browser/fesm5/platform-browser.js.EmulatedEncapsulationDomRenderer2.applyToHost (platform-browser.js:1157)
    at DomRendererFactory2.push../node_modules/@angular/platform-browser/fesm5/platform-browser.js.DomRendererFactory2.createRenderer (platform-browser.js:1015)

Можете ли вы помочь мне решить эту ошибку или предложить другую реализацию?


РЕДАКТИРОВАТЬ: РЕШЕНИЕ

Лучшая версия @Serhiy предлагает

Таблица:

<table>
  <app-item *ngFor="let item of items" [item]="item" remove-component-tag></app-item>
</table>

Директива:

import { Directive, ElementRef } from '@angular/core';

@Directive({
  selector: '[remove-component-tag]'
})
export class RemoveComponentTagDirective {
  constructor(private el: ElementRef) {

    let element = el.nativeElement;
    let children = el.nativeElement.childNodes;

    setTimeout(()=>{
      let reversedChildren = [];
      children.forEach(child => {
        reversedChildren.unshift(child);
      });
      reversedChildren.forEach(child => {
        element.parentNode.insertBefore(child, element.nextSibling);
      });
      element.remove(element);
    }, 0);

  }
}

Тайм-аут необходим по некоторым причинам и работает даже с 0.

Ответы [ 2 ]

3 голосов
/ 21 июня 2019

Я не вижу правильного «углового» способа сделать это, но вы должны быть в состоянии использовать директивы для очистки вашего HTML во время рендеринга.

Видел этот подход в комментариях здесь: Angular2: рендеринг компонента без тега переноса

Я попробовал это, и это сработало для меня:

Родительский компонент:

<table>

  <div *ngFor="let item of items">
    <app-item [item]="item" remove-wrapper></app-item>  
  </div>

</table>

Дочерний компонент:

<tr>
    <td>
      <img src="https://someimage.com/{{item.img}}.jpg">
    </td>

    <td>
      <h3>{{item.name}}</h3>
    </td>

    <td>
      {{item.description}}
    </td>      

</tr>

<tr>
    <td>
      <img src="https://someimage.com/{{item.img}}.jpg">
    </td>

    <td>
      <h3>{{item.name + ' 2'}}</h3>
    </td>

    <td>
      {{item.description + ' 2'}}
    </td>      

</tr>

Директива:

@Directive({
  selector: '[remove-wrapper]'
})

export class RemoveWrapperDirective {

  constructor(private el: ElementRef) {

    let parent = el.nativeElement.parentElement;
    let children = el.nativeElement.childNodes;

    setTimeout(()=>{
      parent.parentNode.insertBefore(children[1], parent.nextSibling);
      parent.parentNode.insertBefore(children[0], parent.nextSibling);
      parent.remove(parent);
    }, 10);

  }
}

Без тайм-аута у меня произошел сбой.Код можно улучшить, но вы можете начать отсюда.

0 голосов
/ 21 июня 2019

Поможет ли здесь использование синтаксиса компонента вместо директивного синтаксиса?

Вместо:

<ng-container *ngFor="let item of items" [item]="item" app-item></ng-container>

Попробуйте:

<ng-container *ngFor="let item of items">
    <app-item [item]="item"></app-item>
</ng-container> 
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...