Angular2生命周期挂钩适用于本地数据,但不适用于api数据 [英] Angular2 lifecycle hook working on local data, but not api data

查看:63
本文介绍了Angular2生命周期挂钩适用于本地数据,但不适用于api数据的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我制作了以下小程序来展示我的问题.当我使用本地数据填充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屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆