【问题标题】:ngFor don`t show all items immediately after place_changed event from google place autocompletengFor不要在来自google place自动完成的place_changed事件之后立即显示所有项目
【发布时间】:2021-12-30 14:01:05
【问题描述】:

我需要在 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>

感谢您的帮助!

【问题讨论】:

    标签: javascript angular google-maps google-places-api


    【解决方案1】:

    可能您的组件更改检测策略是 OnPush 或 google 自动完成在 zone.js 之外运行:

     changeDetection: ChangeDetectionStrategy.OnPush
    

    由于 items 是数组并且它通过引用存储在内存中,因此您需要手动运行更改检测:

    constructor(private cdr: ChangeDetectorRef)
    
    public addToListSelectedItem() {
      ...
      this.input.nativeElement.value = '';
      this.cdr.detectChanges();
    

    【讨论】:

    • 感谢您的帮助!!
    【解决方案2】:

    更好的办法是使用 RxJS 主题、用于 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 进行更多控制。

    【讨论】:

    • 感谢您的回答,但问题在于在 zone.js 之外运行 google 自动完成功能。阅读 RxJS 主题非常有用!还要感谢有关使用 setValue 的建议。我会稍微改变我的代码)。我还需要 ViewChild 输入来初始化自动完成。
    猜你喜欢
    • 1970-01-01
    • 2021-06-02
    • 2012-09-30
    • 2017-05-29
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多