programing

@viewChild가 작동하지 않음 - property nativeElement of undefined를 읽을 수 없습니다.

itmemos 2023. 10. 14. 09:36
반응형

@viewChild가 작동하지 않음 - property nativeElement of undefined를 읽을 수 없습니다.

다른 요소를 클릭할 때 이 요소에 초점을 맞추기 위해 네이티브 요소에 액세스하려고 합니다(html 속성 "for"와 마찬가지로 -for는 이 유형의 요소에 사용할 수 없습니다).

그러나 오류가 발생합니다.

TypeError: 정의되지 않은 'nativeElement' 속성을 읽을 수 없습니다.

console.log를 nativeElement in으로 시도합니다.ngAfterViewInit()로드되지만 여전히 오류가 발생하도록 합니다.

또한 클릭 이벤트 핸들러에서 nativeElement에 액세스하여 다른 요소를 클릭할 때 요소에 초점을 맞출 수 있습니다. 뷰가 로드되기 전에 컴파일되기 때문에 이것이 이 요소를 망치는 것일까요?

예:

ngAfterViewInit() {
    console.log(this.keywordsInput.nativeElement); // throws an error
}

focusKeywordsInput(){
    this.keywordsInput.nativeElement.focus();
}

전체 코드:

사용 중인 HTML 템플릿의 관련 부분:

<div id="keywords-button" class="form-group" (click)="focusKeywordsInput()">
    <input formControlName="keywords" id="keywords-input" placeholder="KEYWORDS (optional)"/>
    <div class="form-control-icon" id="keywords-icon"></div>
</div>

component.ts:

import { Component, OnInit, AfterViewInit, ViewChild, ElementRef } from '@angular/core';
import {  REACTIVE_FORM_DIRECTIVES, 
          FormGroup, 
          FormBuilder, 
          Validators,
          ControlValueAccessor
        } from '@angular/forms';
import { NumberPickerComponent } from './number-picker.component';
import { DistanceUnitsComponent } from './distance-units.component';
import { MapDemoComponent } from '../shared/map-demo.component';
import { AreaComponent } from './area-picker.component';
import { GoComponent } from './go.component';
import { HighlightDirective } from '../highlight.directive';

@Component({
   selector: 'find-form',
   templateUrl: 'app/find-page/find-form.component.html',
   styleUrls: ['app/find-page/find-form.component.css'],
   directives: [REACTIVE_FORM_DIRECTIVES, 
                NumberPickerComponent, 
                DistanceUnitsComponent, 
                MapDemoComponent, 
                AreaComponent, 
                GoComponent]
})
export class FindFormComponent implements OnInit, AfterViewInit {
   findForm: FormGroup;
   submitted: boolean; // keep track on whether form is submitted
   events: any[] = []; // use later to display form changes
   @ViewChild('keywords-input') keywordsInput;
//comment
   constructor(private formBuilder: FormBuilder, el: ElementRef) {}

   ngOnInit() {
      this.findForm = this.formBuilder.group({
         firstname: ['', [ Validators.required, Validators.minLength(5) ] ],
         lastname: ['', Validators.required],
         keywords: [],
         area: ['', Validators.required],
         address: this.formBuilder.group({
            street: [],
            zip: [],
            city: []
         })
      });

      this.findForm.valueChanges.subscribe(data => console.log('form changes', data));
   }

     ngAfterViewInit() {
    console.log(this.keywordsInput.nativeElement); // throws an error
  }

   focusKeywordsInput(){
      this.keywordsInput.nativeElement.focus();
   }

   save(isValid: boolean) {
      this.submitted = true;
      // check if model is valid
      // if valid, call API to save customer
      console.log(isValid);
   }
}

전체 html 템플릿(관련 없는 probably)

<form class="text-uppercase" [formGroup]="findForm" (ngSubmit)="save(findForm.value, findForm.valid)">
    <div class="row is-heading">
        <div class="col-sm-8 offset-sm-2 col-md-6 offset-md-3 col-lg-4 offset-lg-4 input-group">
            <h2 class="search-filter-heading heading m-x-auto">find vegan</h2>
        </div>
    </div>
    <div class="row has-error-text">
        <div class="col-sm-8 offset-sm-2 col-md-6 offset-md-3 col-lg-4 offset-lg-4 input-group btn-group" style="height:64px;">
            <div style="position: relative; display: inline-block; width: 100%;">
                <multiselect #multiselect></multiselect>
            </div>
        </div>
    </div>
    <div class="row error-text"  [style.display]="multiselect.selectedCategories.length < 1 && submitted ? 'block' : 'none'">
        <div class="col-sm-8 offset-sm-2 col-md-6 offset-md-3 col-lg-4 offset-lg-4 form-group input-group btn-group">
            <small>Please select at least 1 category.</small>
        </div>
    </div>
    <div class="row is-heading">
        <div class="col-sm-8 offset-sm-2 col-md-6 offset-md-3 col-lg-4 offset-lg-4 input-group">
            <h2 class="search-filter-heading heading m-x-auto">within</h2>
        </div>
    </div>
    <div class="row">
        <div class="col-sm-8 offset-sm-2 col-md-6 offset-md-3 col-lg-4 offset-lg-4 input-group btn-group" style="height:64px;">
            <div style="position: relative; display: inline-block;">
                <number-picker #numberPicker></number-picker>
            </div>
            <distance-units></distance-units>
        </div>
    </div>
    <div class="row is-heading">
        <div class="col-sm-8 offset-sm-2 col-md-6 offset-md-3 col-lg-4 offset-lg-4 input-group">
            <h2 class="search-filter-heading heading m-x-auto">of</h2>
        </div>
    </div>
    <div class="row has-error-text">
        <div class="col-sm-8 offset-sm-2 col-md-6 offset-md-3 col-lg-4 offset-lg-4 input-group btn-group" style="height:64px;">
            <div style="position: relative; display: inline-block; width: 100%;">
                <my-area></my-area>
            </div>
        </div>
    </div>
    <div class="row error-text"  [style.display]="multiselect.selectedCategories.length < 1 && submitted ? 'block' : 'none'">
        <div class="col-sm-8 offset-sm-2 col-md-6 offset-md-3 col-lg-4 offset-lg-4 form-group input-group btn-group">
            <small [hidden]="findForm.controls.firstname.valid || (findForm.controls.firstname.pristine && !submitted)">Please enter an area.</small>
        </div>
    </div>
    <div class="row is-heading">
        <div class="col-sm-8 offset-sm-2 col-md-6 offset-md-3 col-lg-4 offset-lg-4 input-group">
            <h2 class="search-filter-heading heading m-x-auto">keywords</h2>
        </div>
    </div>
    <div class="row form-group">
        <div class="col-sm-8 offset-sm-2 col-md-6 offset-md-3 col-lg-4 offset-lg-4 input-group btn-group" style="height:64px;">
            <div style="position: relative; display: inline-block; width: 100%;">
                <div id="keywords-button" class="form-group" (click)="focusKeywordsInput()">
                    <input formControlName="keywords" id="keywords-input" placeholder="KEYWORDS (optional)"/>
                    <div class="form-control-icon" id="keywords-icon"></div>
                </div>
            </div>
        </div>
    </div>
    <div class="row">
        <div class="col-sm-8 offset-sm-2 col-md-6 offset-md-3 col-lg-4 offset-lg-4 input-group btn-group" style="height:64px;">
            <div style="position: relative; display: inline-block; width: 100%;">
                <go></go>
            </div>
        </div>
    </div>
</form>

@ViewChild('keywords-input') keywordsInput;일치하지 않음id="keywords-input"

id="keywords-input"

대신 템플릿 변수가 되어야 합니다.

#keywordsInput

다음과 같이 낙타 케이스를 사용해야 합니다.-템플릿 참조 이름에는 사용할 수 없습니다.

@ViewChild()에서는 템플릿 변수의 이름을 문자열로 지원합니다.

@ViewChild('keywordsInput') keywordsInput;

또는 구성요소 또는 지시 유형:

@ViewChild(MyKeywordsInputComponent) keywordsInput;

https://stackoverflow.com/a/35209681/217408 도 참조

힌트:
keywordsInput이전에 설정되지 않음ngAfterViewInit()라고 합니다.

대상 요소가 숨겨진 요소 안에 있는 경우에도 이 오류가 발생합니다.HTML인 경우:

<div *ngIf="false">
    <span #sp>Hello World</span>
</div>

당신의.@ViewChild('sp') sp정의되지 않습니다.

해결책

그런 경우에는 사용하지 마십시오.*ngIf.

대신 클래스를 사용하여 요소가 숨겨져 있는 것을 표시/숨깁니다.

<div [class.show]="shouldShow">...</div>

승인된 답변은 모든 면에서 맞으며 앱 구성 요소 중 하나에서 Google Map 렌더를 가져올 수 없는 경우 이 스레드를 우연히 발견했습니다.

이제 각 7+ 이상의 최근 각 버전을 사용하는 경우 다음 ViewChild 선언을 처리해야 합니다.

@ViewChild(selector: string | Function | Type<any>, opts: {
read?: any;
static: boolean;
})

자, 흥미로운 부분은 정의에 따라 말하는 정적 값입니다.

  • static - 변경 탐지를 실행하기 전에 쿼리 결과를 확인하려면 True입니다.

이제 지도를 렌더링하기 위해 다음을 사용했습니다.

@ViewChild('map', { static: true }) mapElement: any;
  map: google.maps.Map;

저도 비슷한 문제가 있었지만, 제 경우에는 그 문제를 읽으려고 했습니다.nativeElement내부에ngOnInit방법:

@ViewChild('userNameInput') userNameInput: ElementRef<HTMLInputElement>;
...
ngOnInit(): void {
    this.userNameInput.nativeElement.focus();
}

로 변경했습니다.ngAfterViewInit그리고 모든게 잘 작동했습니다.

@ViewChild('userNameInput') userNameInput: ElementRef<HTMLInputElement>;
...
ngAfterViewInit(): void {
    this.userNameInput.nativeElement.focus();
}

이 오류는 조건으로 래핑된 요소를 대상으로 지정하려고 할 때 발생합니다.

따라서 [hidden] 대신 ngIf를 사용하면 TypeError: 정의되지 않은 'nativeElement' 속성을 읽을 수 없습니다.

[숨김], 클래스를 사용합니다.쇼든 클래스든*ngif 대신 숨습니다.

<button (click)="displayMap()" class="btn btn-primary">Display Map</button>

   <div [hidden]="!display">
      <div #mapContainer id="map">Content to render when condition is true.</div>
   </div>

조건()으로 때 이할 수 <div *ngIf="canShow"> <p #target>Targeted Element</p></div>

canShow렌더링 시 false이며, Angular는 렌더링되지 않기 때문에 해당 요소를 가져올 수 없습니다. 따라서 오류가 나타납니다.

중 는 는 A 를 입니다.display: hidden 대신 *ngIf따라서 요소는 렌더링되지만 조건이 충족될 때까지 숨겨집니다.

Github에서 자세히 보기

제 경우에는 그냥 확인만 하고 있습니다.

` @ViewChild('myinput') myInputField: ElementRef;

ngAfterViewInit() {

if (this.myInputField !== undefined) {
  this.myInputField.nativeElement.focus();
}

}

DOM이 로드되기 전에 이러한 요소를 호출하면 이러한 오류가 나타납니다.항상 사용:

 window.onload = function(){
     this.keywordsInput.nativeElement.focus();
 }

*ngif 제거

제 경우 @ViewChild 요소 안에서 저는 *ngIf를 아래와 같이 사용하고 있었습니다.

<ul class="menu" *ngIf="isMenuOpen" #menu>
  <li *ngFor="let data of dropdownData" (click)="onClickOfVal(data)">
    {{ data }}
  </li>
</ul>

업데이트된 코드

<ul class="menu" [style.display]="isMenuOpen ? 'block' : 'none'" #menu>
  <li *ngFor="let data of dropdownData" (click)="onClickOfVal(data)">
    {{ data }}
  </li>
</ul>

아래와 같이 캔버스를 초기화하는 것은 TypeScript/Angular 솔루션에 적합합니다.

const canvas = <HTMLCanvasElement> document.getElementById("htmlElemId"); 

const context = canvas.getContext("2d"); 

단순합니다 : 이 디렉토리를 가져옵니다.

import {Component, Directive, Input, ViewChild} from '@angular/core';

언급URL : https://stackoverflow.com/questions/39158922/viewchild-not-working-cannot-read-property-nativeelement-of-undefined

반응형