Angular 2 - 使用异步http请求进行插值和绑定

时间:2016-01-26 16:33:46

标签: asynchronous binding httprequest angular string-interpolation

我是Angular 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调用完成,或者如何直接在模板中插入“模型”值而不绑定到另一个组件?

谢谢!

2 个答案:

答案 0 :(得分: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()); 
    }
}

请参阅this answer了解有效工作人员。

答案 1 :(得分:0)

本讨论列出了一些策略https://github.com/angular/angular/issues/6674#issuecomment-174699245

  

这个问题有很多含义。在某些情况下,可以在框架之外管理可观察量。

     

一个。您可以在引导之前扫描所有可观察对象

     

B中。然后,Bootstrap会在将对象传递给顶级组件之前扫描所有可观察对象。

     

℃。您还可以将组件中的changeDetection更改为在输入更改时触发或手动触发更改检测器。

     

d。如果您正在使用| async,那么只有在您不想使用.subscribe时才应该在顶层使用它,但您真的应该使用.subscribe。

     

电子。如果你在任何地方使用| async,那么你真正在做的是将渲染的控制权转换为可观察对象,这意味着我们回到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之外运行操作,因此它不会告诉angular触发chanes。例如,

// 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
  }
}