Удалить селектор элементов HTML хоста, созданный компонентом angular

В angular 2 svg-rect - это компонент, который создает rect, как показано ниже,

<svg height="550" width="450" x="0" y="0">
    <g id="svgGroup">
        <svg-rect>
        <!--template bindings={}-->
            <rect x="10" y="10" height="100" width="100" fill="red" stroke="#000" stroke-width="2"></rect>
        <!--template bindings={}-->
        </svg-rect>
        <svg-rect>
        <!--template bindings={}-->
            <rect x="10" y="10" height="100" width="100" fill="red" stroke="#000" stroke-width="2"></rect>
        <!--template bindings={}-->
        </svg-rect>
    </g>
</svg>

но это не сделает rect из-за созданных специальных тегов элементов. Если теги svg-rect удалены, он отображает rect

<svg height="550" width="450" x="0" y="0">
    <g id="svgGroup">
        <!--template bindings={}-->
        <rect x="10" y="10" height="100" width="100" fill="red" stroke="#000" stroke-width="2"></rect>
        <!--template bindings={}-->
        <!--template bindings={}-->
        <rect x="10" y="10" height="100" width="100" fill="red" stroke="#000" stroke-width="2"></rect>
        <!--template bindings={}-->
    </g>
</svg>

В angular 1.x есть replace: 'true', который удаляет теги директивы с помощью скомпилированного вывода. Можем ли мы реализовать то же самое в angular2?

Ответ 1

Вместо того, чтобы пытаться избавиться от элемента-хоста, превратите его в тот, который является допустимым SVG, но другим мудрым unaffecting: вместо вашего селектора элементов

selector: "svg-rect"

и соответствующий ему элемент в шаблоне:

template: `...<svg-rect>...</svg-rect>...`

переключиться на селектор атрибутов:

selector: "[svg-rect]"

и добавьте этот атрибут в тег элемента группы:

template: `...<g svg-rect>...</g>...`

Это будет расширяться до:

<svg height="550" width="450" x="0" y="0">
    <g id="svgGroup">
        <g svg-rect>
        <!--template bindings={}-->
            <rect x="10" y="10" height="100" width="100" fill="red" stroke="#000" stroke-width="2"></rect>
        <!--template bindings={}-->
        </g>
        <g svg-rect>
        <!--template bindings={}-->
            <rect x="10" y="10" height="100" width="100" fill="red" stroke="#000" stroke-width="2"></rect>
        <!--template bindings={}-->
        </g>
    </g>
</svg>

который является действительным SVG, который будет отображать. Plnkr

Ответ 2

Другой подход для удаления хоста компонента, который я использую.

Директива remove-host

//remove the host of avatar to be rendered as svg
@Directive({
    selector: '[remove-host]'
})
class RemoveHost {
    constructor(private el: ElementRef) {
    }

    //wait for the component to render completely
    ngOnInit() {
        var nativeElement: HTMLElement = this.el.nativeElement,
            parentElement: HTMLElement = nativeElement.parentElement;
        // move all children out of the element
        while (nativeElement.firstChild) {
            parentElement.insertBefore(nativeElement.firstChild, nativeElement);
        }
        // remove the empty element(the host)
        parentElement.removeChild(nativeElement);
    }
}

Использование этой директивы; <avatar [name]="hero.name" remove-host></avatar>

В директиве remove-host все дочерние элементы nativeElement вставлены перед хостом, а затем удаляется элемент хоста.

Пример примера Gist
На основе варианта использования может быть несколько проблем с производительностью.

Ответ 3

Другой подход, по которому мы можем получить шаблон компонента из компонента.
Сначала мы создаем компонент, чей тег мы надеемся удалить из браузера (мы не пытаемся удалить тег здесь.)

@Component({
  selector: 'tl-no-tag',
  template: `
    <template #tmp>
      <p>{{value}}</p>
    </template>`,
  styleUrls: []
})
export class TlNoTagComponent {
  @ViewChild('tmp') tmp: any;
  value = 5;
}

Затем в другом шаблоне компонента мы пишем:

<tl-no-tag #source></tl-no-tag> <!-- This line can be placed anywhere -->
<template [ngTemplateOutlet]="source.tmp"></template> <!-- This line will be placed where needed -->

Тогда у нас в браузере что-то вроде этого:

<tl-no-tag></tl-no-tag>
<p>5</p>

Итак, мы вывели <p>{{value}}</p> из TlNoTagComponent. <tl-no-tag></tl-no-tag> будет продолжать существовать, но не будет блокировать какие-либо css или svg-thing.

Ответ 4

Чтобы процитировать Angular от 1 до Angular 2 док-документа стратегии обновления:

Директивы, которые заменяют свой хост-элемент (replace: true директивы в Angular 1), не поддерживаются в Angular 2. Во многих случаях эти директивы могут быть обновлены до стандартных директив компонентов.

Бывают случаи, когда регулярные директивы компонентов не работают, в таких случаях могут использоваться альтернативные подходы. Например, для svg см. https://github.com/mhevery/ng2-svg