Angular 2 viewchild not working - cannot read property nativeElement of undefined

匿名 (未验证) 提交于 2019-12-03 02:30:02

问题:

I have this component called multiselect.component and I access one of its html elements (<select id="category-select">) in the .ts file.

multiselect.component.html:

<select id="category-select" multiple class="form-control">     <option value="1">Meat</option>     <option value="2">Dairy</option>     <option value="3">Confectionary</option>     <option value="4">Dessert</option>     <option value="7">Baking</option>     <option value="6">Grocers</option>     <option value="5">Restaurants</option>     <option value="8">Condiments</option>     <option value="9">beverages</option> </select> <div class="form-control-icon" id="keywords-icon"></div> 

multiselect.component.ts:

import { Component, OnInit } from '@angular/core';  @Component({     selector: 'multiselect',     templateUrl: 'app/shared/multiselect.component.html',     styleUrls: [ 'app/shared/multiselect.component.css' ] }) export class MultiselectComponent implements OnInit {     items = 'one two three'.split(' ');     selectedCategories;     allSelected;     numberOfCategories = 9;      ngOnInit() {         this.selectedCategories = [];         (<any>$("#category-select")).multiselect({             buttonWidth: '100%',             buttonContainer: '<div style="height: 34px;" />',             buttonClass: 'none',             nonSelectedText: "select categories",             nSelectedText: ' categories',             allSelectedText: "all categories",             selectAllNumber: false,             includeSelectAllOption: true,             disableIfEmpty: true,             onSelectAll: () => {                 this.allSelected = true;             },             onInitialized: () => {              },             onChange: (option, checked) => {                 this.changed();             }         });     }      changed() {         this.selectedCategories = [];         var self = this;          $('#category-select option:selected').each(function () {             self.selectedCategories.push(                 <any>($(this).text(), $(this).val())             )         });         console.log(this.selectedCategories);         if (this.selectedCategories.length < this.numberOfCategories) {             this.allSelected = false;         }     } } 

I think that the way I access it is bad practice by using jquery. I think it can be accessed with @viewChild instead.

So I'm trying to change it like this (I am first just getting rid of the first jquery element accessor then will do the rest later):

import { Component, OnInit, ViewChild } from '@angular/core';  @Component({     selector: 'multiselect',     templateUrl: 'app/shared/multiselect.component.html',     styleUrls: [ 'app/shared/multiselect.component.css' ] }) export class MultiselectComponent implements OnInit {     items = 'one two three'.split(' ');     selectedCategories;     allSelected;     numberOfCategories = 9;      @ViewChild('category-select') select;      ngOnInit() {         this.selectedCategories = [];         this.select.nativeElement.multiselect({             buttonWidth: '100%',             buttonContainer: '<div style="height: 34px;" />',             buttonClass: 'none',             nonSelectedText: "select categories",             nSelectedText: ' categories',             allSelectedText: "all categories",             selectAllNumber: false,             includeSelectAllOption: true,             disableIfEmpty: true,             onSelectAll: () => {                 this.allSelected = true;             },             onInitialized: () => {              },             onChange: (option, checked) => {                 this.changed();             }         });     }      changed() {         this.selectedCategories = [];         var self = this;          $('#category-select option:selected').each(function () {             self.selectedCategories.push(                 <any>($(this).text(), $(this).val())             )         });         console.log(this.selectedCategories);         if (this.selectedCategories.length < this.numberOfCategories) {             this.allSelected = false;         }     } } 

I'm getting this console error:

> EXCEPTION: Error: Uncaught (in promise): EXCEPTION: Error in app/find-page/find-form.component.html:0:56 ORIGINAL EXCEPTION: TypeError: Cannot read property 'nativeElement' of undefined ORIGINAL STACKTRACE: TypeError: Cannot read property 'nativeElement' of undefined     at MultiselectComponent.System.register.context_1.execute.MultiselectComponent.ngOnInit (http://localhost:3000/js/app/shared/Multiselect.component.js:29:32)     at DebugAppView._View_FindFormComponent0.detectChangesInternal (FindFormComponent.ngfactory.js:761:90)     at DebugAppView.AppView.detectChanges (http://localhost:3000/node_modules/@angular/core//bundles/core.umd.js:12586:18)     at DebugAppView.detectChanges (http://localhost:3000/node_modules/@angular/core//bundles/core.umd.js:12691:48)     at DebugAppView.AppView.detectViewChildrenChanges (http://localhost:3000/node_modules/@angular/core//bundles/core.umd.js:12612:23)     at DebugAppView._View_FindPageComponent0.detectChangesInternal (FindPageComponent.ngfactory.js:41:8)     at DebugAppView.AppView.detectChanges (http://localhost:3000/node_modules/@angular/core//bundles/core.umd.js:12586:18)     at DebugAppView.detectChanges (http://localhost:3000/node_modules/@angular/core//bundles/core.umd.js:12691:48)     at DebugAppView.AppView.detectViewChildrenChanges (http://localhost:3000/node_modules/@angular/core//bundles/core.umd.js:12612:23)     at DebugAppView.AppView.detectChangesInternal (http://localhost:3000/node_modules/@angular/core//bundles/core.umd.js:12597:18) ERROR CONTEXT: [object Object] 

Why am I getting that error?

After changing to AfterViewInit, I'm now getting this error:

platform-browser.umd.js:937 Error: Uncaught (in promise): EXCEPTION: Error in app/find-page/find-form.component.html:13:30 ORIGINAL EXCEPTION: TypeError: Cannot read property 'length' of undefined ORIGINAL STACKTRACE: TypeError: Cannot read property 'length' of undefined     at DebugAppView._View_FindFormComponent0.detectChangesInternal (FindFormComponent.ngfactory.js:890:72)     at DebugAppView.AppView.detectChanges (http://localhost:3000/node_modules/@angular/core//bundles/core.umd.js:12586:18)     at DebugAppView.detectChanges (http://localhost:3000/node_modules/@angular/core//bundles/core.umd.js:12691:48)     at DebugAppView.AppView.detectViewChildrenChanges (http://localhost:3000/node_modules/@angular/core//bundles/core.umd.js:12612:23)     at DebugAppView._View_FindPageComponent0.detectChangesInternal (FindPageComponent.ngfactory.js:41:8)     at DebugAppView.AppView.detectChanges (http://localhost:3000/node_modules/@angular/core//bundles/core.umd.js:12586:18)     at DebugAppView.detectChanges (http://localhost:3000/node_modules/@angular/core//bundles/core.umd.js:12691:48)     at DebugAppView.AppView.detectViewChildrenChanges (http://localhost:3000/node_modules/@angular/core//bundles/core.umd.js:12612:23)     at DebugAppView.AppView.detectChangesInternal (http://localhost:3000/node_modules/@angular/core//bundles/core.umd.js:12597:18)     at DebugAppView.AppView.detectChanges (http://localhost:3000/node_modules/@angular/core//bundles/core.umd.js:12586:18) ERROR CONTEXT: [object Object]     at resolvePromise (http://localhost:3000/node_modules/zone.js/dist/zone.js:538:32)     at http://localhost:3000/node_modules/zone.js/dist/zone.js:515:14     at ZoneDelegate.invoke (http://localhost:3000/node_modules/zone.js/dist/zone.js:323:29)     at Object.onInvoke (http://localhost:3000/node_modules/@angular/core//bundles/core.umd.js:9245:45)     at ZoneDelegate.invoke (http://localhost:3000/node_modules/zone.js/dist/zone.js:322:35)     at Zone.run (http://localhost:3000/node_modules/zone.js/dist/zone.js:216:44)     at http://localhost:3000/node_modules/zone.js/dist/zone.js:571:58     at ZoneDelegate.invokeTask (http://localhost:3000/node_modules/zone.js/dist/zone.js:356:38)     at Object.onInvokeTask (http://localhost:3000/node_modules/@angular/core//bundles/core.umd.js:9236:45)     at ZoneDelegate.invokeTask (http://localhost:3000/node_modules/zone.js/dist/zone.js:355:43) 

The error seems to be in FindFormComponent.

FindFormComponent is just the form that has the multiselect (a form to fill out which will then find products).

Here is the relevant html from the FindFormComponent that utilises length:

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

回答1:

You need to change

ngOnInit() {     this.selectedCategories = [];     this.select.nativeElement.multiselect({ 

to

ngAfterViewInit() {     this.selectedCategories = [];     this.select.nativeElement.multiselect({ 

The nativeElement isn't available before the view is initialized.



易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!