지시문에서 호스트 구성 요소에 액세스하는 방법은 무엇입니까?
마크업이 다음과 같습니다.
<my-comp myDirective></my-comp>
지시문에서 컴포넌트 인스턴스에 접근할 수 있는 방법이 있습니까?
으로 의 할 수 .MyComponent
MyDirective
, 이상적으로 위의 HTML에 아무것도 추가하지 않습니다.
그냥 주사를 놓으시면 됩니다.
class MyDirective {
constructor(private host:MyComponent) {}
심각한 한계는 구성 요소의 종류를 미리 알아야 한다는 것입니다.
https://github.com/angular/angular/issues/8277 도 참조
종류를 미리 모를 때를 대비한 몇 가지 방법도 제공합니다.
사용자 지정 구성 요소에서 속성 지시어를 사용하려면 해당 구성 요소를 추상 클래스에서 추상 클래스 유형을 구성 요소 유형으로 'forwardRef' 확장할 수 있습니다.이렇게 하면 (지침 내에서) 추상 클래스에서 angular의 DI를 선택할 수 있습니다.
추상 클래스:
export abstract class MyReference {
// can be empty if you only want to use it as a reference for DI
}
사용자 지정 구성요소:
@Component({
// ...
providers: [
{provide: MyReference, useExisting: forwardRef(() => MyCustomComponent)}
],
})
export class MyCustomComponent extends MyReference implements OnInit {
// ...
}
지시:
@Directive({
selector: '[appMyDirective]'
})
export class CustomDirective{
constructor(private host:MyReference) {
console.log(this.host);
// no accessing private properties of viewContainerRef to see here... :-)
}
}
이렇게 하면 추상 클래스를 확장하는 모든 구성 요소에서 지시문을 사용할 수 있습니다.
물론 이는 사용자 자신의 구성요소에서만 작동합니다.
지시사항은 구성요소에 적용할 수 있는 일반적인 지시사항이 될 수 있습니다.그래서, 그 경우, 컨스트럭터에 부품을 주입하는 것은 불가능할 것이고, 그래서 여기에 그와 같은 방법을 위한 다른 한 가지 방법이 있습니다.
합니다.ViewContainerRef
n로
constructor(private _viewContainerRef: ViewContainerRef) { }
그 다음에 그걸 사용하도록 해요.
let hostComponent = this._viewContainerRef["_data"].componentView.component;
이것은 깃허브 이슈에서 가져온 것으로 매력처럼 작용합니다.단점은 구성 요소를 사전에 알아야 하지만, 사용 중인 방법을 알아야 합니다.
import { Host, Self, Optional } from '@angular/core';
export class ExampleDirective {
constructor(
@Host() @Self() @Optional() public hostCheckboxComponent : MdlCheckboxComponent,
@Host() @Self() @Optional() public hostSliderComponent : MdlSliderComponent
) {
if(this.hostCheckboxComponent) {
console.log("host is a checkbox");
} else if(this.hostSliderComponent) {
console.log("host is a slider");
}
}
크레딧: https://github.com/angular/angular/issues/8277#issuecomment-323678013
지시 제네릭을 만드는 방법 중 하나는 구성 요소의 템플릿 참조를 지시에 @Input으로 전달하는 것입니다.이것은 html을 조금 더 추가하지만 제가 시도한 다른 많은 해킹들보다 더 잘 작동했습니다.
@Directive({selector: '[myDirective]'})
export class MyDirective implements OnInit {
@Input() componentRef: any;
@Input() propName: string;
ngOnInit(){
if (this.componentRef != null) {
// Access component properties
this.componentRef[this.propName];
}
}
}
보기의 사용량:
<!-- Pass component ref and the property name from component as inputs -->
<app-component #appComponentRef myDirective [componentRef]="appComponentRef" [propName]="'somePropInComponent'" .... >
또한 다른 지시사항들과 함께 작동합니다.exportAs를 의 속성으로 사용@Directive
지시 인스턴스에 대한 참조를 가져오는 데코레이터.
<form #myForm="ngForm" myDirective [componentRef]="myForm" [propName]="'ngSubmit'" ....>
ViewContainerRef를 사용하여 호스트 구성 요소에 액세스할 수 있습니다.
constructor(private el: ViewContainerRef) {}
ngOnInit() {
const _component = this.el && this.el.injector && this.el.injector.get(MyComponent);
}
참조 : https://angular.io/api/core/ViewContainerRef
Angular 12의 경우, 이 코멘트는 더러운 해결책에 대한 올바른 방향을 나에게 가리켰습니다.이것이 원칙적으로 이 문제를 해결하는 좋은 방법이 아니라는 것은 잘 알고 있지만, 여러 모듈에 걸쳐 문제가 분리되어 있기 때문에 제 사용 사례에서는 쓰기 시간에 무엇인지 알지 못한 채 구성 요소 인스턴스에 액세스할 수 있어야 했습니다.
TL;DR:
class MyDirective {
constructor(private vcRef: ViewContainerRef) {}
private getHostComponent(): any {
return this.vcRef._lContainer[0][8];
}
}
에 할 수 .ViewContainerRef
의_lContainer
컨테이너와 연관된 상태를 나타내는 property.이것.LContainer
인덱스 0(내부 상수)의 엔트리를 갖습니다.LView
컨테이너가 구성 요소 노드에 있는 경우.
LView
, 다시, 는 위치 8(내부 상수)에 항목이 있습니다. 이 항목은 연결된 구성 요소가 비루트 구성 요소(예: non-root component element)인 경우 구성 요소 인스턴스에 대한 참조입니다.<app-*
컨텍스트 구성 수 있습니다.lContainer[HOST][CONTEXT]
.
설명과 함께 복사 붙여넣기에 대한 긴 답변:
class MyDirective {
constructor(private vcRef: ViewContainerRef) {}
private getHostElementFromViewContainerRef(): unknown | null {
// TL;DR of the below method:
// return this.vcRef._lContainer[0][8];
// Inspired by https://stackoverflow.com/questions/46014761/how-to-access-host-component-from-directive#comment119646192_48563965
const vcRef = this.vcRef as any; // We're accessing private properties so we cast to any to avoid awkward TS validation issues
// We fetch the component associated with the element this directive is attached to by navigating via the ViewContainerRef.
// The VCRef contains a reference to the LContainer, which represents the state associated with the container:
// https://github.com/angular/angular/blob/12.2.x/packages/core/src/render3/interfaces/container.ts#L65
const lContainer = vcRef._lContainer;
if (!lContainer) {
return null;
}
// LView has all its elements defined as array elements, with keys hardcoded to numeric constants:
// https://github.com/angular/angular/blob/12.2.x/packages/core/src/render3/interfaces/view.ts#L26-L57
// We care about two of them:
const HOST = 0; // https://github.com/angular/angular/blob/12.2.x/packages/core/src/render3/interfaces/view.ts#L29
const CONTEXT = 8; // https://github.com/angular/angular/blob/12.2.x/packages/core/src/render3/interfaces/view.ts#L37
// LContainer is an array, with the element at the HOST position being an LView if the container is on a Component Node.
// This means that this may not work if this directive is declared on a native HTML element.
// Note that LContainer uses the same indexes as LView, so it's the same HOST constant as declared in the LView interfaces file.
// https://github.com/angular/angular/blob/12.2.x/packages/core/src/render3/interfaces/container.ts#L66-L72
const lView = lContainer[HOST];
if (!lView) {
return null;
}
// For a non-root component, the context is the component instance.
// So if this directive is correctly attached to an Angular Component (e.g. `<app-*`),
// this array entry will contain the instance of that component.
// https://github.com/angular/angular/blob/12.2.x/packages/core/src/render3/interfaces/view.ts#L173-L180
const contextElement = lView[CONTEXT];
return contextElement || null;
}
}
저는 이게 좋아요, Angular 9 & 11에서 작동해요.
element는 element .DOM
, 현재 객체인재 Component의다를 동적으로 할 수 .
지정 에 입니다.
__component
nativeElement드,nativeElement.__component
인에Directve
;내보내기 클래스FromItemComponentBase{contractor(개인 호스트Element:ElementRef){hostElement.nativeElement.__component=this; }
@Component({
selector: 'input-error',
templateUrl: 'component.html'
})
export class FromItemErrorComponent extends FromItemComponentBase {
constructor(private hostElement: ElementRef) {
super(hostElement);
}
}
@Component({
selector: 'input-password',
templateUrl: 'component.html'
})
export class FromItemPasswordComponent extends FromItemComponentBase {
constructor(private hostElement: ElementRef) {
super(hostElement);
}
}
@Directive({selector: 'input-error,input-password,input-text'})
export class FormInputDirective {
component:FromItemComponentBase;
constructor(private hostElement: ElementRef) {
this.component=hostElement.nativeElement.__component;
}
}
constructor(private vcRef: ViewContainerRef){
let parentComponent=(<any>this.vcRef)._view.context;
}
viewContainerRef: ViewContainerRef in Constructor 및 다음 코드(this.viewContainerRef as any)가 있습니다._hostLview[8]이(가) 완벽하게 작동합니다.그러나 아래에 설명된 대로 구성 요소 참조를 Input 매개 변수로 지시에 전달하는 것이 좋습니다.
<my-comp myDirective [hostComponent]="hostComponent"></my-comp>
내 CompComponent.ts에서
hostComponent = this;
내 지시사항.ts에서,
@Input() hostComponent: Component;
참고: 이것은 해킹성이 있으며 Angular의 향후 버전에서는 작동하지 않을 가능성이 높습니다.Angular 10에서는 다음과 같이 호스트 컴포넌트에 접근할 수 있었습니다.
하게 @Sunil Garg 의ViewContainerRef
지침에 따라 다음과 같이 합니다.
constructor(_viewContainerRef: ViewContainerRef)
다음과 같이 호스트 구성 요소를 가져옵니다.
let hostComponent = (<any>_viewContainerRef)._lContainer[0][8];
여기서 두 가지 해결책을 시도했습니다.
Michiel Windey )abstract class
될 구성 에 대한 및로서 )및 Anthony것용)@Host() @Self() @Optional()
).
둘 다 Angular 11과 함께 일합니다.
두 모두 이 없으며, 되지 않은 입니다를 사용하는 에 대비할 수
두 번째는 기존 구성요소를 변경하지 않고 접근할 수 있는 장점이 있습니다.하지만 실제로 투입되는 부품에 따라 처리해야 할 검사와 특수 케이스가 많이 필요할 것 같습니다.
첫 번째는 구성요소를 수정해야 하는 불편함이 있지만 인터페이스(추상 클래스)에서 지시어에 사용할 모든 필드와 메서드를 정의할 수 있으므로 어떤 구성요소가 주입되는지 확인할 필요 없이 하나의 매개변수로 액세스할 수 있습니다.
따라서 사용 사례에 따라 선택이 달라집니다.
언급URL : https://stackoverflow.com/questions/46014761/how-to-access-host-component-from-directive
'programing' 카테고리의 다른 글
깃 푸시가 "빠른 방향으로 이동하지 않음"을 거부했습니다. (0) | 2023.09.21 |
---|---|
초기 데이터 로드(angularjs) (0) | 2023.09.21 |
자동 배선 종속성을 주입하지 못했습니다. (0) | 2023.09.21 |
부트스트랩에서 용기의 수직 중심을 맞추는 방법은? (0) | 2023.09.16 |
PDO: 백슬래시가 포함된 DB에서 필드 선택 (0) | 2023.09.16 |