@*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
'programing' 카테고리의 다른 글
| Excel 셀에서 형식이 지정된 텍스트에 태그가 있는 HTML 텍스트 (0) | 2023.05.24 |
|---|---|
| 성능 테스트를 위한 정확한 시간 측정 (0) | 2023.05.24 |
| 스토리보드 및 ARC가 없는 Xcode (0) | 2023.05.24 |
| NPM 글로벌 설치 "모듈을 찾을 수 없음" (0) | 2023.05.24 |
| 장고 모델에서 전화번호를 저장하는 가장 좋은 방법은 무엇입니까? (0) | 2023.05.24 |