ngFor 不会在 google 地点自动完成的 place_changed 事件后立即显示所有项目
ngFor don`t show all items immediately after place_changed event from google place autocomplete
我需要在 place_changed 事件后将结果添加到列表中。我在我找到位置的输入下方显示列表。事件有效,结果被推送到数组项。但问题是新添加的项目不会立即显示。它会在一段时间后或当我单击显示此输入的表单时显示。
.ts:
@ViewChild('locationInput', { static: true }) input: ElementRef;
autocomplete;
items = [];
ngOnInit() {
this.autocomplete = new google.maps.places.Autocomplete(this.input.nativeElement, this.localityOptions);
this.autocomplete.addListener('place_changed', () => {
this.addToListSelectedItem();
});
}
public addToListSelectedItem() {
if (this.input.nativeElement.value) {
this.items.push(this.input.nativeElement.value);
this.input.nativeElement.value = '';
}
}
.html:
<input
#locationInput
class="shadow-none form-control"
formControlName="locality"
placeholder=""
[attr.disabled]="locationForm.controls['region'].dirty ? null : true"
/>
<div *ngFor="let item of items; let index = index">
<div class="listOfLocation">
<div class="itemList">{{ item }}</div>
<img [src]="icons.cross" class="delete-button-img" alt="edit-icon" (click)="deleteTask(index)" />
</div>
</div>
感谢您的帮助!
可能您的组件更改检测策略是 OnPush 或 google 自动完成 运行ning 在 zone.js:
之外
changeDetection: ChangeDetectionStrategy.OnPush
并且由于项目是数组并且它通过引用存储在内存中,您需要运行手动更改检测:
constructor(private cdr: ChangeDetectorRef)
public addToListSelectedItem() {
...
this.input.nativeElement.value = '';
this.cdr.detectChanges();
更好的方法是使用 RxJS Subject、items$ 的 Observable 并使用异步管道。异步管道就像魔术一样工作,涉及更新模板:-)!
@ViewChild('locationInput', { static: true }) input: ElementRef;
autocomplete;
itemsSubject$ = new Subject<any[]>();
items$ = this.itemsSubject$.asObservable();
// Use a separate array to hold the items locally:
existing = [];
ngOnInit() {
this.autocomplete = new google.maps.places.Autocomplete(this.input.nativeElement, this.localityOptions);
this.autocomplete.addListener('place_changed', () => {
this.addToListSelectedItem();
});
}
public addToListSelectedItem() {
if (this.input.nativeElement.value) {
// Use spread syntax to create a new array with the input value pushed at the end:
this.existing = [...this.existing, this.input.nativeElement.value];
// Send the newly created array to the Subject (this will update the items$ Observable since it is derived from this Subject):
this.itemsSubject$.next(this.existing);
this.input.nativeElement.value = '';
}
}
// I added the deleteTask implementation to show you how this works with the subject:
deleteTask(index: number) {
// The Array "filter" function creates a new array; here it filters out the index that is equally to the given one:
this.existing = this.existing.filter((x, i) => i !== index);
this.itemsSubject$.next(this.existing);
}
并且在模板中:
<input
#locationInput
class="shadow-none form-control"
formControlName="locality"
placeholder=""
[attr.disabled]="locationForm.controls['region'].dirty ? null : true"
/>
<!-- Only difference here is adding the async pipe and using the items$ Observable instead -->
<div *ngFor="let item of items$ | async; let index = index">
<div class="listOfLocation">
<div class="itemList">{{ item }}</div>
<img [src]="icons.cross" class="delete-button-img" alt="edit-icon" (click)="deleteTask(index)" />
</div>
</div>
有关此概念中 RxJS 主题的工作示例,请参阅 https://stackblitz.com/edit/angular-ivy-dxfsoq?file=src%2Fapp%2Fapp.component.ts。
也许超出了这个问题,但既然你使用的是反应形式,为什么不使用 this.locationForm.get('locality').setValue('...') 来设置输入而不是使用 ViewChild 处理输入?然后使用 ViewChild 以这种方式进行更多控制。
我需要在 place_changed 事件后将结果添加到列表中。我在我找到位置的输入下方显示列表。事件有效,结果被推送到数组项。但问题是新添加的项目不会立即显示。它会在一段时间后或当我单击显示此输入的表单时显示。
.ts:
@ViewChild('locationInput', { static: true }) input: ElementRef;
autocomplete;
items = [];
ngOnInit() {
this.autocomplete = new google.maps.places.Autocomplete(this.input.nativeElement, this.localityOptions);
this.autocomplete.addListener('place_changed', () => {
this.addToListSelectedItem();
});
}
public addToListSelectedItem() {
if (this.input.nativeElement.value) {
this.items.push(this.input.nativeElement.value);
this.input.nativeElement.value = '';
}
}
.html:
<input
#locationInput
class="shadow-none form-control"
formControlName="locality"
placeholder=""
[attr.disabled]="locationForm.controls['region'].dirty ? null : true"
/>
<div *ngFor="let item of items; let index = index">
<div class="listOfLocation">
<div class="itemList">{{ item }}</div>
<img [src]="icons.cross" class="delete-button-img" alt="edit-icon" (click)="deleteTask(index)" />
</div>
</div>
感谢您的帮助!
可能您的组件更改检测策略是 OnPush 或 google 自动完成 运行ning 在 zone.js:
之外 changeDetection: ChangeDetectionStrategy.OnPush
并且由于项目是数组并且它通过引用存储在内存中,您需要运行手动更改检测:
constructor(private cdr: ChangeDetectorRef)
public addToListSelectedItem() {
...
this.input.nativeElement.value = '';
this.cdr.detectChanges();
更好的方法是使用 RxJS Subject、items$ 的 Observable 并使用异步管道。异步管道就像魔术一样工作,涉及更新模板:-)!
@ViewChild('locationInput', { static: true }) input: ElementRef;
autocomplete;
itemsSubject$ = new Subject<any[]>();
items$ = this.itemsSubject$.asObservable();
// Use a separate array to hold the items locally:
existing = [];
ngOnInit() {
this.autocomplete = new google.maps.places.Autocomplete(this.input.nativeElement, this.localityOptions);
this.autocomplete.addListener('place_changed', () => {
this.addToListSelectedItem();
});
}
public addToListSelectedItem() {
if (this.input.nativeElement.value) {
// Use spread syntax to create a new array with the input value pushed at the end:
this.existing = [...this.existing, this.input.nativeElement.value];
// Send the newly created array to the Subject (this will update the items$ Observable since it is derived from this Subject):
this.itemsSubject$.next(this.existing);
this.input.nativeElement.value = '';
}
}
// I added the deleteTask implementation to show you how this works with the subject:
deleteTask(index: number) {
// The Array "filter" function creates a new array; here it filters out the index that is equally to the given one:
this.existing = this.existing.filter((x, i) => i !== index);
this.itemsSubject$.next(this.existing);
}
并且在模板中:
<input
#locationInput
class="shadow-none form-control"
formControlName="locality"
placeholder=""
[attr.disabled]="locationForm.controls['region'].dirty ? null : true"
/>
<!-- Only difference here is adding the async pipe and using the items$ Observable instead -->
<div *ngFor="let item of items$ | async; let index = index">
<div class="listOfLocation">
<div class="itemList">{{ item }}</div>
<img [src]="icons.cross" class="delete-button-img" alt="edit-icon" (click)="deleteTask(index)" />
</div>
</div>
有关此概念中 RxJS 主题的工作示例,请参阅 https://stackblitz.com/edit/angular-ivy-dxfsoq?file=src%2Fapp%2Fapp.component.ts。
也许超出了这个问题,但既然你使用的是反应形式,为什么不使用 this.locationForm.get('locality').setValue('...') 来设置输入而不是使用 ViewChild 处理输入?然后使用 ViewChild 以这种方式进行更多控制。