75

Angular 1.x では、UI-Router がこのための主要なツールでした。「解決」値の promise を返すことにより、ルーターは、promise が完了するのを待ってから、ディレクティブをレンダリングします。

あるいは、Angular 1.x では、null オブジェクトはテンプレートをクラッシュさせません。そのため、一時的に不完全なレンダリングが気にならない場合は、最初は空のモデル オブジェクトを設定$digestした後にレンダリングするために使用できます。promise.then()

2 つの方法のうち、可能であればビューの読み込みを待ち、リソースを読み込めない場合はルート ナビゲーションをキャンセルしたいと思います。これにより、「ナビゲートしない」という作業が省けます。編集:これは、この質問がこれを行うためにAngular 2の先物互換またはベストプラクティスの方法を要求し、可能であれば「エルビスオペレーター」を避けるように要求することを特に意味することに注意してください! したがって、私はその答えを選択しませんでした。

ただし、これら 2 つの方法はどちらも Angular 2.0 では機能しません。確かに、これには標準的なソリューションが計画されているか、利用可能です。誰がそれが何であるか知っていますか?

@Component() {
    template: '{{cats.captchans.funniest}}'
}
export class CatsComponent {

    public cats: CatsModel;

    ngOnInit () {
        this._http.get('/api/v1/cats').subscribe(response => cats = response.json());
    }
}

次の質問は同じ問題を反映している可能性があります: Angular 2 render template after the PROMISE with data is loaded . 質問にはコードや受け入れられた回答が含まれていないことに注意してください。

4

6 に答える 6

86

{{model?.person.name}}モデルがそうでないのを待ってからレンダリングする必要がundefinedあります。

Angular 2 では、この?.構文をElvis operatorと呼んでいます。ドキュメントでの参照は見つけにくいため、変更/移動した場合に備えて、そのコピーを次に示します。

Elvis 演算子 ( ?. ) と null プロパティ パス

Angular の「Elvis」演算子 ( ?. ) は、プロパティ パス内の null 値や未定義の値から保護する流暢で便利な方法です。ここでは、currentHero が null の場合にビューのレンダリングの失敗から保護します。

The current hero's name is {{currentHero?.firstName}}

問題とこの特定の解決策について詳しく説明しましょう。

次のデータ バインドされたタイトル プロパティが null の場合はどうなりますか?

The title is {{ title }}

ビューは引き続きレンダリングされますが、表示される値は空白です。「The title is」のみが表示され、その後には何も表示されません。それは合理的な行動です。少なくともアプリはクラッシュしません。

null ヒーローの firstName を表示している次の例のように、テンプレート式にプロパティ パスが含まれているとします。

The null hero's name is {{nullHero.firstName}}

JavaScript は null 参照エラーをスローし、Angular も同様です:

TypeError: Cannot read property 'firstName' of null in [null]

さらに悪いことに、ビュー全体が消えます。

ヒーロー プロパティが決して null であってはならないと信じていれば、これは合理的な動作であると主張できます。null であってはならないのに null である場合は、キャッチして修正する必要があるプログラミング エラーが発生しています。例外をスローすることは正しいことです。

一方、特にデータが最終的に到着することがわかっている場合は、プロパティ パスの null 値が問題ない場合もあります。

データを待っている間、ビューは問題なくレンダリングされ、null プロパティ パスは title プロパティと同様に空白として表示されるはずです。

残念ながら、currentHero が null の場合、アプリはクラッシュします。

NgIf を使用してその問題を回避するコーディングを行うことができます

<!--No hero, div not displayed, no error --> <div *ngIf="nullHero">The null hero's name is {{nullHero.firstName}}</div>

または、プロパティ パスの一部を && でチェーンしようとすることもできます。これは、式が最初の null に遭遇したときに救済されることがわかっているためです。

The null hero's name is {{nullHero && nullHero.firstName}}

これらのアプローチにはメリットがありますが、特にプロパティ パスが長い場合は扱いにくくなる可能性があります。abcd のような長いプロパティ パスのどこかで null をガードすることを想像してみてください。

Angular の「Elvis」演算子 ( ?. ) は、プロパティ パスの null を防ぐためのより流暢で便利な方法です。最初の null 値に到達すると、式は抜け出します。ディスプレイは空白ですが、アプリは回転し続け、エラーはありません。

<!-- No hero, no problem! --> The null hero's name is {{nullHero?.firstName}}

長いプロパティ パスでも完全に機能します。

a?.b?.c?.d

于 2016-01-12T07:48:25.647 に答える
38

パッケージ@angular/routerにはResolveルートのプロパティがあります。そのため、ルート ビューをレンダリングする前にデータを簡単に解決できます。

参照: https://angular.io/docs/ts/latest/api/router/index/Resolve-interface.html

2017 年 8 月 28 日現在のドキュメントの例:

class Backend {
  fetchTeam(id: string) {
    return 'someTeam';
  }
}

@Injectable()
class TeamResolver implements Resolve<Team> {
  constructor(private backend: Backend) {}

  resolve(
    route: ActivatedRouteSnapshot,
    state: RouterStateSnapshot): Observable<any>|Promise<any>|any {
    return this.backend.fetchTeam(route.params.id);
  }
}

@NgModule({
  imports: [
    RouterModule.forRoot([
      {
        path: 'team/:id',
        component: TeamCmp,
        resolve: {
          team: TeamResolver
        }
      }
    ])
  ],
  providers: [TeamResolver]
})
class AppModule {}

データが解決されて返されるまで、ルートはアクティブになりません。

コンポーネント内の解決されたデータへのアクセス

実行時にコンポーネント内から解決されたデータにアクセスするには、2 つの方法があります。したがって、ニーズに応じて、次のいずれかを使用できます。

  1. route.snapshot.paramMap文字列を返す、または
  2. route.paramMapあなたができるObservableを返します.subscribe()

例:

  // the no-observable method
  this.dataYouResolved= this.route.snapshot.paramMap.get('id');
  // console.debug(this.licenseNumber);

  // or the observable method
  this.route.paramMap
     .subscribe((params: ParamMap) => {
        // console.log(params);
        this.dataYouResolved= params.get('id');
        return params.get('dataYouResolved');
        // return null
     });
  console.debug(this.dataYouResolved);

それが役立つことを願っています。

于 2016-07-05T21:01:27.133 に答える
7

編集: angular チームは @Resolve デコレータをリリースしました。それがどのように機能するかについては、まだ明確にする必要がありますが、それまでは、他の誰かの関連する回答をここで取り上げ、他のソースへのリンクを提供します。


編集: この回答は Angular 2 BETA でのみ機能します。この編集時点では、ルーターは Angular 2 RC 用にリリースされていません。代わりに、Angular 2 RC を使用する場合は、への参照を に置き換えてrouterrouter-deprecated引き続きベータ ルーターを使用してください。

これを実装する Angular2 の将来の方法は、@Resolve デコレーターを介することになります。それまでは、CanActivateBrandon Roberts によると、最も近い複製は Component decorator です。https://github.com/angular/angular/issues/6611を参照してください

ベータ 0 は解決された値をコンポーネントに提供することをサポートしていませんが、計画されており、ここで説明されている回避策もあります: Using Resolve In Angular2 Routes

ベータ 1 の例は、http: //run.plnkr.co/BAqA98lphi4rQZAd/#/resolvedにあります。非常によく似た回避策を使用しますが、より正確にはRouteDataオブジェクトを使用しますRouteParams

@CanActivate((to) => {
    return new Promise((resolve) => {
        to.routeData.data.user = { name: 'John' }

また、ネストされた/親ルートの「解決された」値にアクセスするための回避策の例、および 1.x UI-Router を使用したことがある場合に期待されるその他の機能もあることに注意してください。

Angular Injector 階層は現在 CanActivate デコレータで利用できないため、これを達成するために必要なサービスを手動で注入する必要があることに注意してください。インジェクターをインポートするだけで、新しいインジェクター インスタンスが作成され、 からプロバイダーにアクセスする必要がないbootstrap()ため、ブートストラップされたインジェクターのアプリケーション全体のコピーを保存することをお勧めします。このページの Brandon の 2 番目の Plunk リンクは、良い出発点です: https://github.com/angular/angular/issues/4112

于 2016-01-21T14:59:22.580 に答える
4

オブザーバーでローカル値を設定する

...また、エラーを避けるためにダミー データで値を初期化することを忘れないでくださいuninitialized

export class ModelService {
    constructor() {
      this.mode = new Model();

      this._http.get('/api/v1/cats')
      .map(res => res.json())
      .subscribe(
        json => {
          this.model = new Model(json);
        },
        error => console.log(error);
      );
    }
}

これは、Model がデータの構造を表すデータ モデルであることを前提としています。

パラメーターのないモデルは、すべての値が初期化された (ただし空である) 新しいインスタンスを作成する必要があります。そうすれば、データが受信される前にテンプレートがレンダリングされても、エラーはスローされません。

理想的には、不必要な http リクエストを避けるためにデータを永続化したい場合は、サブスクライブできる独自のオブザーバーを持つオブジェクトにこれを配置する必要があります。

于 2016-01-13T21:27:20.380 に答える
3

私が見つけた素晴らしい解決策は、UI で次のようなことを行うことです。

<div *ngIf="vendorServicePricing && quantityPricing && service">
 ...Your page...
</div

次の場合のみ:vendorServicePricingとがロードされquantityPricingserviceページがレンダリングされます。

于 2017-06-22T18:31:39.993 に答える