Angular2生命周期挂钩适用于本地数据,但不适用于api数据 [英] Angular2 lifecycle hook working on local data, but not api data
问题描述
我制作了以下小程序来展示我的问题.当我使用本地数据填充div时,我的 largestHeight
方法运行得很好,并且在正确的时间,但是当我使用API数据时, largestHeight
方法运行得太早了,并且在插入数据之前完成.
I have made the following small program that shows my problem. When I use local data to populate my div, my largestHeight
method runs just fine and at the right time, but when I use API data, the largestHeight
method runs too soon and is finished before the data is inserted.
这两个组件是整个程序.我已经在HTML模板的主要组件中标记了一个需要更改的变量,以查看两种数据类型之间的区别.(我试图花两小时的时间来编写这两个代码,但是最后,即使我确信它应该很简单,我还是无法使它正常工作):(
These two components are the whole program. I have marked in the main components HTML template the one variable that needs to be changed to see the difference between the two data types. (I have tried to make a plunker of these two pieces of code for 6 hours, but at last, I could not get it to work, even though I am sure it should be quite straight forward) :(
主要组件
import { Component, OnInit, ElementRef, QueryList, ViewChildren, ViewChild, Renderer, AfterViewInit } from '@angular/core';
import { Http } from '@angular/http';
import 'rxjs/Rx';
export interface IHeadlines {
userId: number;
id: string;
title: string;}
export interface GroupPosts {
title: string;
posts: IHeadlines[];}
@Component({
selector: 'test-main3',
template: `
<div id="main_container" #main_container>
<div id="one" #containers>
<test-child3 [data]="localdata"></test-child3> <!-- Change "localdata" to "apidata" to see the difference -->
</div>
<div id="two" #containers>
***** <br>
*****
</div>
</div>
`,
styles: [`
#main_container {
background-color: #cc66ff;
height:100px;
}
#one {
background-color: #669966;
position:absolute;
margin-left: 33.5%;
}
#two {
background-color: #ff99cc;
position:absolute;
margin-left: 5%;
}
`],
})
export class Main3Component implements OnInit {
@ViewChildren('containers', {read: ElementRef})
public divs: QueryList<ElementRef>
@ViewChild('main_container')
public mainContainerRef: ElementRef;
apidata: IHeadlines[];
localdata = [
{ id: 'text1', title: 'up' },
{ id: 'text2', title: 'down' },
{ id: 'text3', title: 'down' },
{ id: 'text4', title: 'up' },
{ id: 'text5', title: 'down' },
{ id: 'text6', title: 'up' },
{ id: 'text7', title: 'up' },
{ id: 'text8', title: 'down' },
{ id: 'text9', title: 'up' },
{ id: 'text10', title: 'down' }
];
constructor(private _http: Http, private _renderer:Renderer) { }
getPosts() {
const url = 'https://jsonplaceholder.typicode.com/albums';
return this._http.get(url)
.map(x => x.json());
}
ngOnInit() {
this.getPosts()
.subscribe(x => this.apidata = x);
}
ngAfterViewInit() {
this.largestHeight();
}
largestHeight() {
console.log("Parent ngAfterViewInit");
let largestHeight = this.divs.reduce((topHeight, divValue) => {
let currentDiv = divValue.nativeElement.getBoundingClientRect();
return (currentDiv.height > topHeight ? currentDiv.height : topHeight);
}, 0);
this._renderer.setElementStyle(this.mainContainerRef.nativeElement, 'height', largestHeight + 40 + 'px');
this.divs.forEach((names) => {
this._renderer.setElementStyle(names.nativeElement, 'height', largestHeight + 'px');
console.log(largestHeight);
});
}
}
子组件
import { Component, OnInit, Input, SimpleChanges } from '@angular/core';
import { IHeadlines, GroupPosts } from '../main3.component';
@Component({
selector: 'test-child3',
template: `
<div *ngFor="let headlines of data">
{{headlines.id}} {{headlines.title}} <br>
</div>
`,
styles: ['div {color: white;}']
})
export class Child3Component implements OnInit {
@Input() data: IHeadlines[];
groupPosts: GroupPosts[];
constructor() { }
ngOnInit() {
}
ngOnChanges(changes: SimpleChanges) {
if (changes['data']) {
this.groupPosts = this.groupByCategory(this.data);
}
}
groupByCategory(data: IHeadlines[]): GroupPosts[] {
if (!data) return
const categories = new Set(data.map(x => x.title));
const result = Array.from(categories).map(x => ({
title: x,
posts: data.filter(post => post.title === x)
}));
return result;
}
}
感谢任何尝试提供帮助的人!
Thanks to anyone for trying to help!
推荐答案
我想您需要在渲染元素后调用 largestHeight
函数.
I guess you need to call largestHeight
function after rendering elements.
您可以通过以下方式解决:
You can work around this way:
import 'rxjs/add/operator/first';
...
constructor(private ngZone: NgZone) { }
ngOnInit() {
this.getPosts()
.subscribe(x => {
this.apidata = x;
this.ngZone.onMicrotaskEmpty.first().subscribe(() => {
this.largestHeight();
});
});
}
Plunker Example
这篇关于Angular2生命周期挂钩适用于本地数据,但不适用于api数据的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!