web-dev-qa-db-ja.com

Angular 4コンポーネントngOnInitは各ルートリクエストで呼び出されません

私は最近、Angular 4 from Angular 1.5に飛び込み始めました。ユーザールートを操作し、サービスからユーザーコンポーネントにAPIデータをプルしています。

コンポーネントは、リクエストごとに更新される1. *のコントローラーとは異なり、静的なままであるように見えます。

新しいルートリクエストごとにngOnInit関数を呼び出す方法はありますか?

私のユーザーコンポーネントクラス:

// url structure: /user/:id
export class UserComponent implements OnInit {

    constructor(private route: ActivatedRoute) {}

    ngOnInit() {

      // doesn't log new id on route change
      let id = this.route.snapshot.params['id'];
      console.log(id);

      this.route.params
        .switchMap(params => this.userService.getUser(params['id']))
        .subscribe(user => {
          // logs new id on route change
          let id = this.route.snapshot.params['id'];
          console.log(id);

          this.user = user
        });
    }
}

[〜#〜] update [〜#〜]

私のシナリオに最適だと思う解決策を見つけました。私の質問に対するいくつかの回答とコメント、およびさらなる調査に基づいて、ルートを購読することが進むべき道のようです。これが私の更新されたコンポーネントです:

export class UserComponent {

  user;
  id;

  constructor(
    private userService: UserService,
    private route: ActivatedRoute
  ) {}


  ngOnInit() {
    this.route.params
      .subscribe(params => this.handleRouteChange(params));
  }

  handleRouteChange(params) {
    this.id = params['id'];

    switch (this.id) {
      case '1':
        console.log('User 1');
        break;

       case '2':
        console.log('User 2');
        break;

       case '3':
        console.log('User 3');
        break;
    }

    this.userService.getUser(this.id).
      subscribe(user => this.user = user);
  }

}
7
Rob

Angularは、ルートが同じであるがパラメーターが変更されている場合、新しいコンポーネントをインスタンス化するのではなく、デフォルトで同じコンポーネントを再利用することを好みます。

朗報!これはカスタマイズ可能な動作です。独自の RouteReuseStrategy を実装することで、新しいコンポーネントインスタンスを強制的にインスタンス化できます。

export class MyRouteReuseStrategy extends DefaultRouteReuseStrategy {
  shouldReuseRoute(next: ActivatedRouteSnapshot, current: ActivatedRouteSnapshot): boolean {
    let name = next.component && (next.component as any).name;
    return super.shouldReuseRoute(next, current) && name !== 'UserComponent';
  }
}

モジュール内:

@NgModule({
  ...
  providers:[{
      provide: RouteReuseStrategy,
      useClass: MyRouteReuseStrategy}]
  ...
})
export class AppModule {}

(このコードは多かれ少なかれ この記事 から取られています。特にnameプロパティのチェックはあまり正確ではないかもしれません...)

同じコンポーネントを復元する場合、パフォーマンスが低下する可能性があることに注意してください。したがって、スナップショットの代わりにobservablesプロパティを使用したほうがよいかもしれません。

2
n00dl3

こんにちはあなたはこのようにswitchMapを使用する必要があります:

this.sub = this.route.paramMap
  .switchMap((params: ParamMap) =>
  this.firebaseService.getProductsByCategory(params.get('category'))).subscribe(products => {
  this.products = products;
  this.count = products.length;
});

これは私のために働きます。

1
Francisco

URLは「...?id = 1」または「../:id」のようになり、GETパラメーターが変更されるたびにコンポーネントがIDをログに記録するようにしますか?問題は ここ について話されています。私が見つけたより良い解決策は ここ です。私はそれを自分でテストしていませんが、これはうまくいくはずです。

2番目のリンクは、コンポーネント内のルート変更をサブスクライブする方法を示しています。これは基本的に、あなたがやろうとしていることだと思います。これにより、ngOnInit内でGETパラメータの変更を処理できるようになります。最初にURLに移動したときにルートサブスクライブが実行されるかどうかわからないため、ルートイベントを処理する関数でdoCheck()を呼び出し、ngOnInitを変更することをお勧めします。 ngAfterContentInit

ngOnInitは 変更検出 でのみ動作し、GETの変更はそれをトリガーしないようです。これは私にとって驚くべきことです。

Tl; dr-コンストラクターでルート変更イベントをサブスクライブし、発行されたイベントを処理する関数を作成します。この関数は、ngOnInit()にあるロジックを保持する必要があります。

0
Michael