我是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调用完成,或者如何直接在模板中插入“模型”值而不绑定到另一个组件?
谢谢!
答案 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
}
您也可以不包含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
}
}