11

私はアンギュラ2を使い慣れていません。非同期http要求と補間によるバインディングに問題があります。角2 - 非同期http要求による補間とバインド

は、ここに私のコンポーネントです:

テンプレートは、「モデル」はまだ設定されていないので、私はエラーを取得し、レンダリングされ
@Component({ 
    selector: 'info', 
    template: `<h1>{{model.Name}}</h1>` 
}) 
export class InfoComponent implements OnInit { 

    model: any; 

    constructor(
     private _service: BackendService 
    ) { } 

    ngOnInit() { 
     if (this.model == null) { 
      this._service.observableModel$.subscribe(m => this.model = m); 
      this._service.get(); 
     }  
    } 
} 

私はこの非常に醜いハックでの問題解決:

@Component({ 
    selector: 'info', 
    template: ` 
    <template ngFor #model="$implicit" [ngForOf]="models | async"> 
    <h1>{{model.Name}}</h1> 
    </template> 
    ` 
}) 
export class NeadInfoComponent implements OnInit { 

    models: Observable<any>; 

    constructor(
     private _service: BackendService 
    ) { } 

    ngOnInit() { 
     if (this.models == null) { 
      this._service.observableModel$.subscribe(m => this.models = Observable.of([m])); 
      this._service.get(); 
     }  
    } 
} 

を私の質問は:結合することなく、私のHTTP呼び出しが完了するまで、テンプレートのレンダリングを延期するか、どのようにテンプレートで直接「モデル」の値を補間する方法別のコンポーネントに?

ありがとうございます!

答えて

12

あなたのサーバーからオブジェクトを返却する場合は、使用することができますsafe navigation (previously "Elvis") operator(?。)テンプレートで:

@Component({ 
    selector: 'info', 
    template: `<h1>{{model?.Name}}</h1>` 
}) 
export class InfoComponent implements OnInit { 
    model: any; 
    constructor(private _service: BackendService) { } 

    ngOnInit() { 
     this._service.getData().subscribe(m => this.model = m); 
     // getData() looks like the following: 
     // return this._http.get('....') // gets JSON document 
     //  .map(data => data.json()); 
    } 
} 

は作業plunkerためthis answerを参照してください。

+1

ありがとうございました!エルヴィスはトリックをやった!しかし、私はまだレンダリングの流れを理解していません。テンプレートは、コンポーネントのプロパティに変更があるたびにレンダリングされますか? –

+2

@TonyAlexanderHildは、角の変化の検出(イベントごとに実行されます)では、デフォルトですべてのビュー/テンプレートのバインディングがダーティチェックされます。つまり、変更が確認されます。サーバーからデータが返されると、それがイベントなので、変更検出が実行されます。 'model.Name'はダーティーチェックされ、変更されていることがわかります。そのため、AngularはDOMを更新します。 Angularがブラウザーに制御を戻した後、DOMの変更が表示され、画面に表示されている内容が更新されます。 –

+0

ありがとう@MarkRajcok!今は明らかです。 –

0

この議論は質問は、多くの意味を持っているhttps://github.com/angular/angular/issues/6674#issuecomment-174699245

いくつかの戦略を示しています。場合によっては、オブザーバブルをフレームワーク外で管理する必要があります。あなたは

B.ブートストラップは、トップレベルのコンポーネントにオブジェクトを渡す前に、すべての観測をスキャンブートストラップ前に

A.あなたは、すべての観測をスキャンすることができます。

C.入力が変更されたとき、または変更検出器を手動でトリガーするときに、コンポーネント内のchangeDetectionをトリガーするように変更することもできます。

D. | asyncを使用している場合は、.subscribeを使用したくない場合はトップレベルでのみ使用するべきですが、実際には.subscribeを使用してください。

E.あなたが本当にやっていることは、observablesへのレンダリングの制御を反転させることです。これはAngular1日間のカスケード変更で戻ってきたので、C、 D、B、またはA

ChangeDetectionStrategy現在のところ動作していないようです。コンポーネントをDetachedとして簡単に設定します。

また、ngOnInitライフサイクルフックを使用して、変更検出ツリーからコンポーネントを削除することもできます。 this.ref.detach();を実行する必要があります。 refはChangeDetectorRef

ngOnInit() { 
    this.ref.detach(); 
    } 
    makeYourChanges() { 
    this.ref.reattach(); // attach back to change detector tree 

    this.data.value = Math.random() + ''; // make changes 

    this.ref.detectChanges(); // check as dirty 

    this.ref.detach(); // remove from tree 
    // zone.js triggers changes 
    } 

ChangeDetectorRef

を介して注入された場合またzone.jsが含まれており、手動でのすべての変更を制御することはできません。また、NgZoneを注入してzone.jsの外で操作を実行することもできます。例えば、

// this example might need a refactor to work with rxjs 5 
export class Timeflies { 
    pos = 'absolute'; 
    color = 'red'; 
    letters: LetterConfig[]; 
    constructor(
    private service: Message, 
    private el: ElementRef, 
    private zone: NgZone) { 

    } 
    ngOnInit() { 
    // initial mapping (before mouse moves) 
    this.letters = this.service.message.map(
     (val, idx) => ({ 
     text: val, 
     top: 100, 
     left: (idx * 20 + 50), 
     index: idx 
     }) 
    ); 
    this.zone.runOutsideAngular(() => { 
     Observable 
     .fromEvent(this.el.nativeElement, 'mousemove') 
     .map((e: MouseEvent) => { 
      //var offset = getOffset(this.el); 

      // subtract offset of the element 
      var o = this.el.nativeElement.getBoundingClientRect(); 

      return { 
      offsetX: e.clientX - o.left, 
      offsetY: e.clientY - o.top 
      }; 
     }) 
     .flatMap(delta => { 
      return Observable 
      .fromArray(this.letters 
       .map((val, index) => ({ 
       letter: val.text, 
       delta, 
       index 
       }))); 
     }) 
     .flatMap(letterConfig => { 
      return Observable 
      .timer((letterConfig.index + 1) * 100) 
      .map(() => ({ 
       text: letterConfig.letter, 
       top: letterConfig.delta.offsetY, 
       left: letterConfig.delta.offsetX + letterConfig.index * 20 + 20, 
       index: letterConfig.index 
      })); 
     }) 
     .subscribe(letterConfig => { 
      // to render the letters, put them back into app zone 
      this.zone.run(() => this.letters[letterConfig.index] = letterConfig); 
     }); 

    });//zone 
    } 
} 
関連する問題