将组件动态附加到 Angular 中的 div 5
Dynamically append component to div in Angular 5
我有这个
https://angular-dynamic-component-append.stackblitz.io/
我设法动态附加了一个元素,但它没有被编译。
我看了很多教程,比如 this
但这并不是我真正需要的。他们经常使用标签符号来标识容器。
我需要将组件附加到可能具有的任何元素
我的自定义指令。
我还需要使用指令的绑定值来控制附加元素上的 [hidden] 属性。
目标
- 覆盖现有组件的行为:
- 将属性添加到 show/hide
- 添加 class 以自定义外观
- 减少html编码
- 无需编写整个组件
<my-comp></mycomp>
- 不需要知道 class
- 更改 class 名称时的自动行为
- 更改应用指令的元素
- 最终目标是添加一个 class 到容器元素
预期来源
<div [myDirective]="myBoolean">
<p>some content</p>
</div>
预计编译
<div [myDirective]="myBoolean" class="myDirectiveClass1">
<p>some content</p>
<someComponent [hidden]="myBoolean" class="myDirectiveClass2"></someComponent>
</div>
有办法实现吗?
提前致谢
很简单。我只是给你举个例子。
请阅读加载器指令中的注释。
https://github.com/garapa/studying/tree/master/loader
编辑:
你的组件:
export class LoaderComponent {
loading;
constructor() { }
}
你的指令
export class LoaderDirective implements OnDestroy {
private componentInstance: ComponentRef<LoaderComponent> = null;
@Input()
set appLoader(loading: boolean) {
this.toggleLoader(loading);
}
constructor(
private viewContainerRef: ViewContainerRef,
private componentFactoryResolver: ComponentFactoryResolver
) { }
toggleLoader(loading: boolean) {
if (!this.componentInstance) {
this.createLoaderComponent();
this.makeComponentAChild();
}
this.componentInstance.instance.loading = loading;
}
private createLoaderComponent() {
const componentFactory = this.componentFactoryResolver.resolveComponentFactory(LoaderComponent);
this.componentInstance = this.viewContainerRef.createComponent(componentFactory);
}
private makeComponentAChild(){
const loaderComponentElement = this.componentInstance.location.nativeElement;
const sibling: HTMLElement = loaderComponentElement.previousSibling;
sibling.insertBefore(loaderComponentElement, sibling.firstChild);
}
ngOnDestroy(): void {
if (this.componentInstance) {
this.componentInstance.destroy();
}
}
}
你的模块
@NgModule({
...
entryComponents: [
LoaderComponent
]
})
这是我的工作方式
import {
Renderer2,
Directive,
Input,
ElementRef,
OnChanges,
ViewEncapsulation
} from "@angular/core";
import { MatSpinner } from "@angular/material";
@Directive({
selector: "[myDirective]"
})
export class MyDirective {
@Input()
set myDirective(newValue: boolean) {
console.info("myDirectiveBind", newValue);
if (!!this._$matCard) {
const method = newValue ? "removeClass" : "addClass";
this.renderer[method](this._$matCard, "ng-hide");
}
this._myDirective = newValue;
}
private _myDirective: boolean;
private _$matCard;
constructor(private targetEl: ElementRef, private renderer: Renderer2) {
this._$matCard = this.renderer.createElement('mat-card');
const matCardInner = this.renderer.createText('Dynamic card!');
this.renderer.addClass(this._$matCard, "mat-card");
this.renderer.appendChild(this._$matCard, matCardInner);
const container = this.targetEl.nativeElement;
this.renderer.appendChild(container, this._$matCard);
}
}
import {
Component,
ElementRef,
AfterViewInit,
ViewEncapsulation
} from '@angular/core';
@Component({
selector: 'card-overview-example',
templateUrl: 'card-overview-example.html',
styleUrls: ['card-overview-example.css']
})
export class CardOverviewExample {
hideMyDirective = !1;
constructor(private _elementRef: ElementRef) { }
getElementRef() {
return this._elementRef;
}
ngAfterViewInit() {
let element = this._elementRef.nativeElement;
let parent = element.parentNode;
element.parentNode.className += " pippo";
}
}
.ng-hide {
display: none;
}
<mat-card>Simple card</mat-card>
<div class="text-center">
<button (click)="hideMyDirective = !hideMyDirective">
Toggle show dynamic card
</button>
</div>
<br />
<span>hideMyDirective: {{hideMyDirective}}</span>
<hr />
<div class="myDiv" [myDirective]="hideMyDirective">
<ul>
<li>My content</li>
</ul>
</div>
要插入组件的组件html文件内:
<div #target>
</div>
要插入组件的组件ts文件里面:
'Component_to_insert' -> 是要插入到另一个组件中的组件。
import { Component_to_insert } from 'path';
import { Component, ViewChild, ViewContainerRef, ComponentFactoryResolver, AfterViewInit } from '@angular/core';
@Component({
selector: 'component-name',
templateUrl: 'component.html',
styleUrls: ['component.scss'],
entryComponents: [Component_to_insert]
})
export class ManagetemplatesPanelComponent implements AfterViewInit {
@ViewChild('target', { read: ViewContainerRef }) entry: ViewContainerRef;
constructor(private resolver: ComponentFactoryResolver) { }
ngAfterViewInit() {
this.createComponent();
}
createComponent() {
this.entry.clear();
const factory = this.resolver.resolveComponentFactory(Component_to_insert);
const componentRef = this.entry.createComponent(factory);
}
}
我有这个
https://angular-dynamic-component-append.stackblitz.io/
我设法动态附加了一个元素,但它没有被编译。 我看了很多教程,比如 this
但这并不是我真正需要的。他们经常使用标签符号来标识容器。
我需要将组件附加到可能具有的任何元素 我的自定义指令。
我还需要使用指令的绑定值来控制附加元素上的 [hidden] 属性。
目标
- 覆盖现有组件的行为:
- 将属性添加到 show/hide
- 添加 class 以自定义外观
- 减少html编码
- 无需编写整个组件
<my-comp></mycomp>
- 不需要知道 class
- 更改 class 名称时的自动行为
- 更改应用指令的元素
- 最终目标是添加一个 class 到容器元素
- 无需编写整个组件
预期来源
<div [myDirective]="myBoolean">
<p>some content</p>
</div>
预计编译
<div [myDirective]="myBoolean" class="myDirectiveClass1">
<p>some content</p>
<someComponent [hidden]="myBoolean" class="myDirectiveClass2"></someComponent>
</div>
有办法实现吗?
提前致谢
很简单。我只是给你举个例子。
请阅读加载器指令中的注释。
https://github.com/garapa/studying/tree/master/loader
编辑:
你的组件:
export class LoaderComponent {
loading;
constructor() { }
}
你的指令
export class LoaderDirective implements OnDestroy {
private componentInstance: ComponentRef<LoaderComponent> = null;
@Input()
set appLoader(loading: boolean) {
this.toggleLoader(loading);
}
constructor(
private viewContainerRef: ViewContainerRef,
private componentFactoryResolver: ComponentFactoryResolver
) { }
toggleLoader(loading: boolean) {
if (!this.componentInstance) {
this.createLoaderComponent();
this.makeComponentAChild();
}
this.componentInstance.instance.loading = loading;
}
private createLoaderComponent() {
const componentFactory = this.componentFactoryResolver.resolveComponentFactory(LoaderComponent);
this.componentInstance = this.viewContainerRef.createComponent(componentFactory);
}
private makeComponentAChild(){
const loaderComponentElement = this.componentInstance.location.nativeElement;
const sibling: HTMLElement = loaderComponentElement.previousSibling;
sibling.insertBefore(loaderComponentElement, sibling.firstChild);
}
ngOnDestroy(): void {
if (this.componentInstance) {
this.componentInstance.destroy();
}
}
}
你的模块
@NgModule({
...
entryComponents: [
LoaderComponent
]
})
这是我的工作方式
import {
Renderer2,
Directive,
Input,
ElementRef,
OnChanges,
ViewEncapsulation
} from "@angular/core";
import { MatSpinner } from "@angular/material";
@Directive({
selector: "[myDirective]"
})
export class MyDirective {
@Input()
set myDirective(newValue: boolean) {
console.info("myDirectiveBind", newValue);
if (!!this._$matCard) {
const method = newValue ? "removeClass" : "addClass";
this.renderer[method](this._$matCard, "ng-hide");
}
this._myDirective = newValue;
}
private _myDirective: boolean;
private _$matCard;
constructor(private targetEl: ElementRef, private renderer: Renderer2) {
this._$matCard = this.renderer.createElement('mat-card');
const matCardInner = this.renderer.createText('Dynamic card!');
this.renderer.addClass(this._$matCard, "mat-card");
this.renderer.appendChild(this._$matCard, matCardInner);
const container = this.targetEl.nativeElement;
this.renderer.appendChild(container, this._$matCard);
}
}
import {
Component,
ElementRef,
AfterViewInit,
ViewEncapsulation
} from '@angular/core';
@Component({
selector: 'card-overview-example',
templateUrl: 'card-overview-example.html',
styleUrls: ['card-overview-example.css']
})
export class CardOverviewExample {
hideMyDirective = !1;
constructor(private _elementRef: ElementRef) { }
getElementRef() {
return this._elementRef;
}
ngAfterViewInit() {
let element = this._elementRef.nativeElement;
let parent = element.parentNode;
element.parentNode.className += " pippo";
}
}
.ng-hide {
display: none;
}
<mat-card>Simple card</mat-card>
<div class="text-center">
<button (click)="hideMyDirective = !hideMyDirective">
Toggle show dynamic card
</button>
</div>
<br />
<span>hideMyDirective: {{hideMyDirective}}</span>
<hr />
<div class="myDiv" [myDirective]="hideMyDirective">
<ul>
<li>My content</li>
</ul>
</div>
要插入组件的组件html文件内:
<div #target>
</div>
要插入组件的组件ts文件里面:
'Component_to_insert' -> 是要插入到另一个组件中的组件。
import { Component_to_insert } from 'path';
import { Component, ViewChild, ViewContainerRef, ComponentFactoryResolver, AfterViewInit } from '@angular/core';
@Component({
selector: 'component-name',
templateUrl: 'component.html',
styleUrls: ['component.scss'],
entryComponents: [Component_to_insert]
})
export class ManagetemplatesPanelComponent implements AfterViewInit {
@ViewChild('target', { read: ViewContainerRef }) entry: ViewContainerRef;
constructor(private resolver: ComponentFactoryResolver) { }
ngAfterViewInit() {
this.createComponent();
}
createComponent() {
this.entry.clear();
const factory = this.resolver.resolveComponentFactory(Component_to_insert);
const componentRef = this.entry.createComponent(factory);
}
}