【问题标题】:@viewChild not working - cannot read property nativeElement of undefined@viewChild 不工作 - 无法读取未定义的属性 nativeElement
【发布时间】:2016-08-26 05:33:38
【问题描述】:

我正在尝试访问本机元素,以便在单击另一个元素时专注于它(很像 html 属性“for” - for 不能用于这种类型的元素。

但是我得到了错误:

TypeError: 无法读取未定义的属性“nativeElement”

我尝试在ngAfterViewInit() 中控制台记录nativeElement,以便加载它,但它仍然抛出错误。

我还在单击事件处理程序中访问 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 模板(可能不相关):

<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>

【问题讨论】:

    标签: angular viewchild


    【解决方案1】:

    @ViewChild('keywords-input') keywordsInput; 不匹配 id="keywords-input"

    id="keywords-input"
    

    应该是一个模板变量:

    #keywordsInput
    

    请注意,应使用驼峰式大小写,因为模板引用名称中不允许使用-

    @ViewChild() 支持将模板变量的名称作为字符串:

    @ViewChild('keywordsInput') keywordsInput;
    

    或组件或指令类型:

    @ViewChild(MyKeywordsInputComponent) keywordsInput;
    

    另见https://stackoverflow.com/a/35209681/217408

    提示:
    在调用ngAfterViewInit() 之前未设置keywordsInput

    【讨论】:

    • 如果之前没有设置,之后怎么设置?
    • 如果你的意思是keywordsInput,那么你就不用自己设置了,它是由Angulars变更检测设置的。
    • 使用 ngAfterViewInit() 完成了这项工作!
    • 提示有效!!!在调用 ngAfterViewInit() 之前不要设置“keywordsInput”。
    【解决方案2】:

    如果您的目标元素位于隐藏元素中,您也会收到此错误。如果这是您的 HTML:

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

    您的@ViewChild('sp') sp 将未定义。

    解决方案

    在这种情况下,请不要使用*ngIf

    改为使用一个类来显示/隐藏你被隐藏的元素。

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

    【讨论】:

    • 如果通过 ng-If 隐藏字段,如何访问该字段?因为即使 ngIf 为 true,viewChild 也显示未定义。
    • @AnilUttani 我不记得我对这个例子做了什么,但你能用ngShow 代替吗?
    • @user2023861 您可以使用[class.show]="showSomething" 或逆逻辑[class.hide]="!showSomething"
    • 当我的输入元素位于 Material Tab 组件中时,我遇到了这个问题,在默认情况下不可见的选项卡中(当父组件加载时)。通过将代码从ngAfterView 移动到相关选项卡变为活动状态时运行的事件处理程序来解决此问题。
    • 非常感谢,我是 Angular 新手,这个 *ngIf 解释刚刚救了我
    【解决方案3】:

    接受的答案在所有方面都是正确的,在我无法在我的一个应用程序组件中获得谷歌地图渲染后,我偶然发现了这个线程。

    现在,如果您使用的是最新的 angular 版本,即 7+ 的 angular,那么您将不得不处理以下 ViewChild 声明,即

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

    现在,有趣的部分是静态值,顾名思义就是

    • 静态 - 在更改检测运行之前解析查询结果为真

    现在为了渲染地图,我使用了以下代码,

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

    【讨论】:

    • 我想我正面临你所说的,但我一直收到 undefined,你如何引用 mapElement?
    • @AndresFelipe 为我的输入自动完成我做了这样的:@ViewChild('searchAddress', {static: true}) public address: ElementRef; 和 html &lt;input #searchAddress /&gt; 希望它有帮助
    • 这对我有用。 @ViewChild('gantt_here', { static: true }) ganttContainer!: ElementRef;
    【解决方案4】:

    当您尝试定位包含在条件中的元素时会发生此错误。

    所以,如果我在这里使用 ngIf 代替 [hidden],它会给我 TypeError: Cannot read property 'nativeElement' of undefined

    所以使用 [hidden]、class.show 或 class.hide 代替 *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>
    

    【讨论】:

      【解决方案5】:

      我遇到了类似的问题,但就我而言,我试图在 ngOnInit 方法中读取 nativeElement

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

      我已更改为 ngAfterViewInit,一切正常:

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

      【讨论】:

        【解决方案6】:

        有时,当您尝试定位包含在条件中的元素时,会发生此错误,例如: &lt;div *ngIf="canShow"&gt; &lt;p #target&gt;Targeted Element&lt;/p&gt;&lt;/div&gt;

        在这段代码中,如果 canShow 在渲染时为 false,Angular 将无法获取该元素,因为它不会被渲染,因此会出现错误。

        其中一种解决方案是在元素上使用display: hidden 而不是*ngIf,这样元素就会被渲染,但在满足您的条件之前会一直隐藏。

        阅读更多over at Github

        【讨论】:

        • 还有哪些其他选择?
        【解决方案7】:

        在我的情况下,我只是检查 undefied

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

        ngAfterViewInit() {

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

        }

        【讨论】:

          【解决方案8】:

          如果在加载 DOM 之前调用这些元素,就会出现此类错误。始终使用:

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

          【讨论】:

            【解决方案9】:

            像下面这样初始化画布适用于 TypeScript/Angular 解决方案。

            const canvas = <HTMLCanvasElement> document.getElementById("htmlElemId"); 
            
            const context = canvas.getContext("2d"); 
            

            【讨论】:

              【解决方案10】:

              很简单:导入这个目录

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

              【讨论】:

              • 这不是问题中问题的解决方案。
              猜你喜欢
              • 1970-01-01
              • 1970-01-01
              • 1970-01-01
              • 2020-01-11
              • 2019-08-04
              • 1970-01-01
              • 2018-02-26
              • 2017-12-15
              • 2017-09-28
              相关资源
              最近更新 更多