我有一个使用谷歌地图服务搜索位置的模式。我收到TypeError: Cannot read properties of undefined (reading 'nativeElement')
错误
HTML
<input
type="text"
[ngClass]="{ error_border: submitted && f.location.errors }"
class="form-control"
formControlName="location"
[readonly]="viewMode"
(keydown.enter)="$event.preventDefault()"
placeholder="Search Location"
autocorrect="off"
autocapitalize="off"
spellcheck="off"
#search
/>
TS
export class ListComponent implements OnInit, AfterViewInit {
dbLocation:any;
latitude!: number;
longitude!: number;
zoom!: number;
address!: string;
private geoCoder:any;
searchFlag:boolean = false;
@ViewChild('search' , { static: true }) public searchElementRef!: ElementRef ;
ngOnInit(): void {
}
ngAfterViewInit() {
//----------autocomplete code block------------
//load Places Autocomplete
this.mapsAPILoader.load().then(() => {
// this.setCurrentLocation();
this.geoCoder = new google.maps.Geocoder;
let autocomplete = new google.maps.places.Autocomplete(this.searchElementRef.nativeElement);
autocomplete.addListener("place_changed", () => {
this.ngZone.run(() => {
//get the place result
let place: google.maps.places.PlaceResult = autocomplete.getPlace();
//verify result
if (place.geometry === undefined || place.geometry === null) {
return;
}
//set latitude, longitude and zoom
this.latitude = place.geometry.location.lat();
this.longitude = place.geometry.location.lng();
this.getAddress(this.latitude, this.longitude);
this.zoom = 15;
this.searchFlag = true;
});
});
});
//----------autocomplete code block------------
}
}
我已尝试将{ static: true }
添加到viewChild。还将自动完成代码块从ngOnInit
移动到ngAfterViewInit
。还添加了自动完成代码块的超时。但还是犯了那个错误。
如果输入字段不在ngOnInit
中的模式和自动完成代码块上,它不会给出错误。但我有模态上的形式,其中有位置的输入域。这是一个错误。
我不知道哪种代码组合会起作用。如何解决该错误?
请提供帮助和指导。
编辑模式HTML
<ng-template #formModal let-modal>
<div class="modal-header">
<h5 class="modal-title" id="modal-basic-title">
Form
</h5>
<button
type="button"
class="close"
aria-label="Close"
(click)="modal.dismiss('Cross click')"
>
<span aria-hidden="true">
<i class="fas fa-times"></i>
</span>
</button>
</div>
<div class="modal-body">
<form [formGroup]="form">
<div class="row edit_profile">
<div class="col-sm-12">
<div class="form-group">
<label>Name<b style="color: red" *ngIf="!viewMode">*</b></label>
<input
type="text"
[ngClass]="{ error_border: submitted && f.headline.errors }"
formControlName="headline"
class="form-control"
[readonly]="viewMode"
/>
<div *ngIf="submitted && f.headline.errors" class="text-danger">
<div *ngIf="f.headline.errors.required">
name is required
</div>
</div>
</div>
</div>
<div class="col-sm-7">
<div class="form-group">
<label for="location">Location <b style="color: red" *ngIf="!viewMode">*</b></label>
<div class="custome_input icons date_icon">
<i class="fas fa-map-marker-alt"></i>
<input
type="text"
[ngClass]="{ error_border: submitted && f.location.errors }"
class="form-control"
formControlName="location"
[readonly]="viewMode"
(keydown.enter)="$event.preventDefault()"
placeholder="Search Location"
autocorrect="off"
autocapitalize="off"
spellcheck="off"
#search
/>
</div>
<div *ngIf="submitted && f.location.errors" class="text-danger">
<div *ngIf="f.location.errors.required">Location is required</div>
</div>
</div>
</div>
<div class="form-group btn-group mb-0" *ngIf="!viewMode">
<button
[disabled]="loading"
class="btn"
(click)="onSubmitForm()"
>
<span
*ngIf="loading"
class="spinner-border spinner-border-sm mr-1"
></span>
Save
</button>
</div>
</form>
</div>
</ng-template>
开启模式的TS
open(content) {
this.listModalRef = this.modalService.open(content,{ size: 'lg', backdrop: 'static' });
this.listModalRef.result.then((result) => {
this.closeResult = `Closed with: ${result}`;
}, (reason) => {
this.closeResult = `Dismissed ${this.getDismissReason(reason)}`;
});
setTimeout(() => {
//load Places Autocomplete
this.mapsAPILoader.load().then(() => {
// this.setCurrentLocation();
this.geoCoder = new google.maps.Geocoder;
let autocomplete = new google.maps.places.Autocomplete(this.searchElementRef.nativeElement);
autocomplete.addListener("place_changed", () => {
this.ngZone.run(() => {
//get the place result
let place: google.maps.places.PlaceResult = autocomplete.getPlace();
//verify result
if (place.geometry === undefined || place.geometry === null) {
return;
}
//set latitude, longitude and zoom
this.latitude = place.geometry.location.lat();
this.longitude = place.geometry.location.lng();
this.getAddress(this.latitude, this.longitude);
this.zoom = 15;
this.searchFlag = true;
});
});
});
}, 0)
}
将代码放在模态内->在新组件中。
在这个新组件中,您可以使用@ViewChild来获取元素值或本地html元素。访问(新组件的(ngAfterViewInit((中的本机元素。它不会被定义。
如果您想与父组件(持有模态的组件(通信,请使用@Input/@Output,或使用ngrxStore(调度操作(。
首先,您应该删除{ static: true }
,否则searchElementRef
将始终未定义。
您需要做的下一个更改是将this.mapsAPILoader.load().then(() => { ... }
逻辑从ngAfterViewInit
移动到一个方法,在该方法中您可以确保模态已经初始化。如果您正在使用任何库组件(用于模态(,并且它提供了一个事件(可能是onShown
或show
或其他什么(来标识模态初始化,那么您可以将逻辑放在那里。
简而言之,您需要确保在解析this.mapsAPILoader.load()
promise之前初始化模态,否则您将始终得到未定义的searchElementRef
。
如果以上方法不起作用,那么您需要为您的模态创建一个单独的组件,而不是使用ng-template
。您可以参考本期中的评论