为什么导航并返回后未定义此ElementRef?

时间:2018-08-06 12:18:13

标签: angular

我在其中一个组件(@ViewChild)中引用了favorite-places,这是Google Maps Autocomplete的搜索输入字段。

一切正常,但当我导航到另一个位置时返回favorite-places

这是组件的布局。请注意,有一个[couterLink]="['../select']"可让我导航到另一个位置。

<div *headerContent fxFlex fxLayout="row" fxLayoutAlign="space-between center"
     style="padding-left: 5px; padding-right: 5px;">    

  <div fxLayoutAlign="center center" style="">
    <mat-icon>search</mat-icon>
    <mat-form-field class="form-group">
      <input #search matInput placeholder="Search" autocorrect="off" autocapitalize="off" spellcheck="off" type="text" class="form-control" [formControl]="searchControl">
    </mat-form-field>
  </div>

  <button mat-icon-button [routerLink]="['../select']" [queryParams]="{groupId: groupId}" (click)="addPlace()">
    <mat-icon>check</mat-icon>
  </button>    
</div>

<div>

  <div class="container">
    <agm-map [latitude]="latitude" [longitude]="longitude" [scrollwheel]="false" [zoom]="zoom" style="height:150px; margin-top: 15px;">
      <agm-marker [latitude]="latitude" [longitude]="longitude"></agm-marker>
    </agm-map>
  </div>

  <div>
    <span>PlaceID: {{selectedPlace?.place_id}}</span><br/>
    <span>Name: {{selectedPlace?.name}}</span>
  </div>

</div>

正如我所说,除我进入该地点,离开该地点然后返回该地点以外,其他所有功能均正常。在这种情况下,我会看到此错误:

ERROR Error: Uncaught (in promise): TypeError: Cannot read property 'nativeElement' of undefined
TypeError: Cannot read property 'nativeElement' of undefined
    at favorite-places.component.ts:61
    at ZoneDelegate.push../node_modules/zone.js/dist/zone.js.ZoneDelegate.invoke (zone.js:388)
    at Object.onInvoke (core.js:4062)
    at ZoneDelegate.push../node_modules/zone.js/dist/zone.js.ZoneDelegate.invoke (zone.js:387)
    at Zone.push../node_modules/zone.js/dist/zone.js.Zone.run (zone.js:138)
    at zone.js:872
    ...

这是发生错误的地方:

this.mapsAPILoader.load().then(() => {
    let autocomplete = new google.maps.places.Autocomplete(
      this.searchElementRef.nativeElement, 
      { types: ['establishment'] });

    autocomplete.addListener('place_changed', () => {
      this.ngZone.run(() => {
        // ..
      });
    });
  }
);
export class FavoritePlacesComponent implements OnInit {

  // ..

  @ViewChild("search")
  public searchElementRef: ElementRef;

}

this.searchElementRef似乎在离开该位置后被无效或未定义。回到它并不会重新创建它。对我来说,这似乎是一个生命周期问题,但我不知道如何解决。

2 个答案:

答案 0 :(得分:0)

您需要将nativeElement的用法包含在ngAfterViewInit生命周期挂钩中。

原因是您的代码首次起作用的原因是load()是异步的,并且您的回调是在具有已呈现组件的下一个VM回合中调用的。但是,返回相同路线后,由于已经加载了Maps API,因此从load()返回的承诺会在ngAfterViewInit之前同步解析。

如果负载应始终异步以消除歧义,这是有争议的。

答案 1 :(得分:0)

再次遇到可更换标头的陷阱。

请注意,我使用的是HeaderContentDirective,它会拆下标题并在每次导航事件中重新创建它。

<div *headerContent ..>
    <!-- .. -->
</div>

..

@Directive({
  selector: '[headerContent]',
})
export class HeaderContentDirective implements OnInit {
  constructor(private headerContent: HeaderContentService, private templateRef: TemplateRef<any>) {}

  ngOnInit(): void {
    this.headerContent.setContents(this.templateRef);
  }
}

,然后在我的ApplicationComponent

  ngAfterViewInit(): void {
    this
      .headerContentService
      .contents
      .subscribe(ref => {
        setTimeout(() => {

          if (this.currentHeaderView !== null) {
            this.logger.trace('Destroying currentHeaderView header ..');
            this.currentHeaderView.destroy();
            this.currentHeaderView = null;
          }
          if (ref === null) {
            this.logger.trace('No new header reference ..');
            return;
          }
          this.logger.trace('Creating embedded view ..');
          this.currentHeaderView = this.vcr.createEmbeddedView(ref);
        });
      });
  }

这似乎不允许我在这里做我想做的事情,这也意味着我将不得不将自动完成输入移到其他地方或找到其他解决方法。