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 以这种方式进行更多控制。