programing

@*ngIf에서 자식 보기

sourcejob 2023. 5. 24. 22:05
반응형

@*ngIf에서 자식 보기

질문.

가장 우아한 방법은 무엇입니까?@ViewChild템플릿의 해당 요소가 표시된 후?

다음은 예입니다.플런커도 사용할 수 있습니다.

Component.template.html:

<div id="layout" *ngIf="display">
  <div #contentPlaceholder></div>
</div>

Component.component.ts:

export class AppComponent {

    display = false;
    @ViewChild('contentPlaceholder', { read: ViewContainerRef }) viewContainerRef;

    show() {
        this.display = true;
        console.log(this.viewContainerRef); // undefined
        setTimeout(() => {
            console.log(this.viewContainerRef); // OK
        }, 1);
    }
}

기본적으로 내용이 숨겨져 있는 구성 요소가 있습니다.가 누가가전화때할군때할▁calls를 부를 때.show()방법 그것은 눈에 보이게 됩니다.2완료되기는 Angular 2 변경 감지를 할 수 .viewContainerRef한 모든 을 나는보필요모작든다같정음다리이니합과업을한통▁all▁into다로 포장합니다.setTimeout(()=>{},1)방법이 ?더 정확한 방법이 있습니까?

에 대한 옵션이 있다는 것을 알고 있습니다.ngAfterViewChecked쓸데없는 전화가 너무 많이 걸려요

답변(플렁커)

ViewChild에 대해 설정자 사용:

 private contentPlaceholder: ElementRef;

 @ViewChild('contentPlaceholder') set content(content: ElementRef) {
    if(content) { // initially setter gets called with undefined
        this.contentPlaceholder = content;
    }
 }

는 한 만 요소 참조로 됩니다.*ngIf 되다true.

참고로 Angular 8의 경우 다음을 설정해야 합니다.{ static: false }이는 다른 Angular 버전의 기본 설정입니다.

 @ViewChild('contentPlaceholder', { static: false })

참고: contentPlaceholder가 구성요소인 경우 ElementRef를 구성요소 클래스로 변경할 수 있습니다.

  private contentPlaceholder: MyCustomComponent;

  @ViewChild('contentPlaceholder') set content(content: MyCustomComponent) {
     if(content) { // initially setter gets called with undefined
          this.contentPlaceholder = content;
     }
  }

이 문제를 해결할 수 있는 다른 방법은 변경 디텍터를 수동으로 실행하는 것입니다.

먼주사 놓오시으십을 합니다.ChangeDetectorRef:

constructor(private changeDetector : ChangeDetectorRef) {}

그런 다음 *ngIf를 제어하는 변수를 업데이트한 후 호출합니다.

show() {
        this.display = true;
        this.changeDetector.detectChanges();
    }

앵귤러 8+

당신은 야합해다를 .{ static: false } 선로으항사의 두 @ViewChild이렇게 하면 변경 탐지가 실행된 후 쿼리 결과가 해결되므로@ViewChild값이 변경된 후 업데이트됩니다.

예:

export class AppComponent {
    @ViewChild('contentPlaceholder', { static: false }) contentPlaceholder: ElementRef;

    display = false;

    constructor(private changeDetectorRef: ChangeDetectorRef) {
    }

    show() {
        this.display = true;

        // Required to access this.contentPlaceholder below,
        // otherwise contentPlaceholder will be undefined
        this.changeDetectorRef.detectChanges();

        console.log(this.contentPlaceholder);
    }
}

Stackblitz 예제: https://stackblitz.com/edit/angular-d8ezsn

제 프로젝트에서 ngIf가 입력 요소에 있기 때문에 위의 답변은 저에게 효과가 없었습니다.ngIf가 참일 때 입력에 집중하기 위해 nativeElement 속성에 대한 액세스가 필요했습니다.ViewContainerRef에 nativeElement 특성이 없는 것 같습니다.@ViewChild 설명서에 따라 수행한 작업은 다음과 같습니다.

<button (click)='showAsset()'>Add Asset</button>
<div *ngIf='showAssetInput'>
    <input #assetInput />
</div>

...

private assetInputElRef:ElementRef;
@ViewChild('assetInput') set assetInput(elRef: ElementRef) {
    this.assetInputElRef = elRef;
}

...

showAsset() {
    this.showAssetInput = true;
    setTimeout(() => { this.assetInputElRef.nativeElement.focus(); });
}

ViewChild가 할당되는 데 몇 초가 걸리기 때문에 포커스를 맞추기 전에 setTimeout을 사용했습니다.그렇지 않으면 정의되지 않습니다.

다른 사람들이 언급했듯이, 가장 빠르고 빠른 해결책은 *ngIf 대신 [hidden]을 사용하는 것입니다.이 방법을 사용하면 구성 요소가 만들어지지만 보이지 않으므로 구성 요소에 액세스할 수 있습니다.이것은 가장 효율적인 방법이 아닐 수도 있습니다.

이것은 효과가 있을 수 있지만 당신의 경우에 편리한지 모르겠습니다.

@ViewChildren('contentPlaceholder', {read: ViewContainerRef}) viewContainerRefs: QueryList;

ngAfterViewInit() {
 this.viewContainerRefs.changes.subscribe(item => {
   if(this.viewContainerRefs.toArray().length) {
     // shown
   }
 })
}

또 다른 빠른 "꼼수"(쉬운 해결책)는 *ngIf 대신 [숨김] 태그를 사용하는 것입니다. 이 경우 Angular가 객체를 빌드하고 클래스 아래에 페인트를 칠합니다. 숨겨진 이유가 ViewChild가 문제 없이 작동하는 이유입니다.따라서 성능 문제를 일으킬 수 있는 무겁거나 비싼 항목에는 숨겨진 항목을 사용하지 않는 것이 중요합니다.

  <div class="addTable" [hidden]="CONDITION">

제 목표는 무엇인가를 가정하는 (예: setTimeout) 진부한 방법을 피하는 것이었고, RxJS 맛을 약간 가미한 승인된 솔루션을 위에 구현하게 되었습니다.

  private ngUnsubscribe = new Subject();
  private tabSetInitialized = new Subject();
  public tabSet: TabsetComponent;
  @ViewChild('tabSet') set setTabSet(tabset: TabsetComponent) {
    if (!!tabSet) {
      this.tabSet = tabSet;
      this.tabSetInitialized.next();
    }
  }

  ngOnInit() {
    combineLatest(
      this.route.queryParams,
      this.tabSetInitialized
    ).pipe(
      takeUntil(this.ngUnsubscribe)
    ).subscribe(([queryParams, isTabSetInitialized]) => {
      let tab = [undefined, 'translate', 'versions'].indexOf(queryParams['view']);
      this.tabSet.tabs[tab > -1 ? tab : 0].active = true;
    });
  }

내 시나리오:나는 어떤 것에 대해 행동을 개시하고 싶었습니다.@ViewChild에 .queryParams *ngIf는 다음과 같습니다.@ViewChild요소는 지연과 함께 발생합니다.

작동 방식: combineLatest제공된 각 관측치가 순간 이후 첫 번째 값을 방출하는 경우에만 처음으로 값을 방출합니다.combineLatest구독했습니다.내 제목tabSetInitialized다음과 같은 경우 값을 방출합니다.@ViewChild요소를 설정하는 중입니다.따라서, 나는 아래의 코드의 실행을 지연시킵니다.subscribe天皇가 끝날 *ngIf긍정적으로 변하고 그리고.@ViewChild초기화됩니다.

물론 OnDestroy 구독을 취소하는 것을 잊지 마세요, 저는 그것을 사용합니다.ngUnsubscribe제목:

  ngOnDestroy() {
    this.ngUnsubscribe.next();
    this.ngUnsubscribe.complete();
  }

단순화된 버전인 Google Maps JS SDK를 사용할 때 이와 유사한 문제가 있었습니다.

내 해결책은 다음을 추출하는 것이었습니다.div그리고.ViewChild상위 구성 요소에 사용될 때 사용된 하위 구성 요소를 사용하여 숨김/잠금 해제할 수 있는 자체 하위 구성 요소*ngIf.

전에

HomePageComponent

<div *ngIf="showMap">
  <div #map id="map" class="map-container"></div>
</div>

HomePageComponent구성품

@ViewChild('map') public mapElement: ElementRef; 

public ionViewDidLoad() {
    this.loadMap();
});

private loadMap() {

  const latLng = new google.maps.LatLng(-1234, 4567);
  const mapOptions = {
    center: latLng,
    zoom: 15,
    mapTypeId: google.maps.MapTypeId.ROADMAP,
  };
   this.map = new google.maps.Map(this.mapElement.nativeElement, mapOptions);
}

public toggleMap() {
  this.showMap = !this.showMap;
 }

끝나고

MapComponent

 <div>
  <div #map id="map" class="map-container"></div>
</div>

MapComponent구성품

@ViewChild('map') public mapElement: ElementRef; 

public ngOnInit() {
    this.loadMap();
});

private loadMap() {

  const latLng = new google.maps.LatLng(-1234, 4567);
  const mapOptions = {
    center: latLng,
    zoom: 15,
    mapTypeId: google.maps.MapTypeId.ROADMAP,
  };
   this.map = new google.maps.Map(this.mapElement.nativeElement, mapOptions);
}

HomePageComponent

<map *ngIf="showMap"></map>

HomePageComponent구성품

public toggleMap() {
  this.showMap = !this.showMap;
 }

Angular 9에서 Change Detector Ref를 사용하면 작동합니다.

@ViewChild('search', {static: false})
public searchElementRef: ElementRef;

constructor(private changeDetector: ChangeDetectorRef) {}

//then call this when this.display = true;
show() {
   this.display = true;
   this.changeDetector.detectChanges();
}

저의 경우 div가 템플릿에 존재할 때만 전체 모듈을 로드해야 했습니다. 즉, 콘센트가 ngif 내부에 있다는 것을 의미합니다.이러한 방식으로 각도가 #지국적 요소를 감지할 때마다콘센트는 그 안에 구성요소를 만들었습니다.모듈도 한 번만 로드됩니다.

constructor(
    public wlService: WhitelabelService,
    public lmService: LeftMenuService,
    private loader: NgModuleFactoryLoader,
    private injector: Injector
) {
}

@ViewChild('geolocalisationOutlet', {read: ViewContainerRef}) set geolocalisation(geolocalisationOutlet: ViewContainerRef) {
    const path = 'src/app/components/engine/sections/geolocalisation/geolocalisation.module#GeolocalisationModule';
    this.loader.load(path).then((moduleFactory: NgModuleFactory<any>) => {
        const moduleRef = moduleFactory.create(this.injector);
        const compFactory = moduleRef.componentFactoryResolver
            .resolveComponentFactory(GeolocalisationComponent);
        if (geolocalisationOutlet && geolocalisationOutlet.length === 0) {
            geolocalisationOutlet.createComponent(compFactory);
        }
    });
}

<div *ngIf="section === 'geolocalisation'" id="geolocalisation">
     <div #geolocalisationOutlet></div>
</div>

나는 특히 나의 경우에 lodash에서 연기를 사용하는 것이 많은 의미가 있다고 생각합니다.@ViewChild()안에 있었습니다.async피리를

Angular 8 작업 ChangeDector를 가져올 필요가 없습니다.

ngIf를 사용하면 요소를 로드하지 않고 응용 프로그램에 더 많은 스트레스를 주는 것을 방지할 수 있습니다.ChangeDetector를 사용하지 않고 실행할 수 있는 방법은 다음과 같습니다.

elem: ElementRef;

@ViewChild('elemOnHTML', {static: false}) set elemOnHTML(elemOnHTML: ElementRef) {
    if (!!elemOnHTML) {
      this.elem = elemOnHTML;
    }
}

그런 다음 ngIf 값을 true로 변경할 때 다음 변경 주기만 대기하도록 setTimeout을 사용합니다.

  this.showElem = true;
  console.log(this.elem); // undefined here
  setTimeout(() => {
    console.log(this.elem); // back here through ViewChild set
    this.elem.do();
  });

따라서 추가 라이브러리나 가져오기를 사용하지 않아도 됩니다.

Angular 8 - null 검사 및@ViewChild static: false

비동기 데이터 대기 중인 페이징 제어의 경우

@ViewChild(MatPaginator, { static: false }) set paginator(paginator: MatPaginator) {
  if(!paginator) return;
  paginator.page.pipe(untilDestroyed(this)).subscribe(pageEvent => {
    const updated: TSearchRequest = {
      pageRef: pageEvent.pageIndex,
      pageSize: pageEvent.pageSize
    } as any;
    this.dataGridStateService.alterSearchRequest(updated);
  });
}

정적 옵션이 false로 설정되어 있는지 확인하십시오.

  @ViewChild('contentPlaceholder', {static: false}) contentPlaceholder: ElementRef;

매개 변수를 전달해야 합니다.{ static: false }로.@ViewChild문제를 해결하다

template.vmdk 코드

<div *ngIf="showFirtChild">
  <first-child #firstchildComponent ></first-child>
</div>

.ts 파일로

export class Parent implements {
  private firstChild: FirstchildComponent;

  @ViewChild('firstchildComponent', { static: false }) set content(content: 
  FirstchildComponent) {
     if(content) { 
          this.firstchildComponent = content;
     }
  }

  ShowChild(){
     this.showFirtChild = true;
     if(this.firstchildComponent){
        this.firstchildComponent.YourMethod()
     }
  }
}

저도 Angular 10과 같은 문제가 있었습니다.

내가 사용하려고 하면[hidden]또는*ngIf그 다음에@ViewChild변수는 항상 정의되지 않았습니다.

<p-calendar #calendar *ngIf="bShowCalendar" >
</p-calendar>

웹 페이지에서 제거하지 않고 수정했습니다.
제가 사용한.[ngClass]통제권을 갖게 하기 위해opacity:0그리고 그것을 완전히 치워버립니다.

<style>
  .notVisible {
    opacity: 0;
    left: -1000px;
    position: absolute !important;
  }
</style>

<p-calendar #calendar [ngClass]="{'notVisible': bShowCalendar }" >
</p-calendar>

네, 멍청하고 못생겼지만 문제를 해결했어요

저는 또한 제어장치를 정적으로 만들어야 했습니다.왜 그런지 이해가 안 가..그러나 이 변경 없이는 작동하지 않았습니다.

export class DatePickerCellRenderer {
    @ViewChild('calendar', {static: true }) calendar: Calendar;

탭 인덱스를 설정해야 하는 상황이 발생했습니다.*ngIf

html:

<div #countryConditional1 *ngIf="country=='USA'">                        
  <input id="streetNumber" [(ngModel)]="streetNumber" pInputText>
</div>

ts:

@ViewChild('countryConditional1') set countryConditional1(element) {
  if (element) {
    const container2 = document.querySelector("#someElement");
    container2.querySelector("span > input").setAttribute("tabindex", "18");
  }

하지 않는 것 (), 터전가것같면으않는않음세호지되작출동지하혀전▁if(▁set)않▁(음ter면같▁doesnnot세▁to으지것터▁working'▁with▁at▁be않작는가)@ViewChild라해를 해 보다@ContentChild대신.

언급URL : https://stackoverflow.com/questions/39366981/viewchild-in-ngif

반응형