angular2 ngFor 在 ngOnInit() 上从 api 获取数据时不工作
angular2 ngFor not working while fetching data from api on ngOnInit()
comment.component.ts:
import { Component, OnInit } from '@angular/core';
import { Router} from '@angular/router'
import { Comment } from 'comment entity path'
import {CommentService} from 'comment service path'
import { Observable } from 'rxjs/Observable';
@Component({
template: ` <ul><li *ngFor="let comment of comments|async"> {{comment.Name}}</li></ul>`
})
export class CommentComponent implements OnInit {
comments: Observable<comment[]>;
constructor(private router: Router, private commentService: CommentService) {
}
ngOnInit() {
this.comments = this.getComments();
}
getComments() {
return this.commentService.getComments();
}
}
comment.service.ts
import { Injectable } from '@angular/core';
import { Headers, Http, Response } from '@angular/http';
import { Comment } from 'comment path here';
import { Observable } from 'rxjs/Rx';
import 'rxjs/add/operator/map';
import 'rxjs/add/operator/catch';
@Injectable()
export class CommentService {
private commentUrl = 'api path'; // URL to web api
constructor(private http: Http) {
}
getComments(): Observable<Comment[]> {
return this.http.get(this.commentUrl).map(
(response) => {
let data = response.text() ? response.json():[{}];
if (data) {
console.log(data);
return data;
}
return data;
});
}
}
在 ngOnInit
方法中,我可以获得评论列表,但问题是该列表未使用 HTML 上的 ngFor
进行绑定。这是因为 HTML 在响应之前呈现。但是在刷新页面时数据会自动绑定。我错过了什么吗?
一种解决方案是仅在您的评论加载后显示您的 ul
,然后强制刷新。所以像:
<ul *ngIf="comments"><li *ngFor="let comment of comments">{{comment.Name}}</li></ul>
所以一旦 comments
被加载,Angular 将强制刷新,并且 ul
将被添加到 DOM,此时它将具有每个评论绑定 li
所需的所有数据。
使用异步管道通过 observable 加载数据。
<li *ngFor="let comment of comments | async">
尝试在 ul 标签中添加 ngFor
<ul *ngFor="let comment of comments"><li > {{comment.Name}}</li></ul>`
or
<ul *ngFor="let comment of (comments|async)"> <li> {{comment.Name}}</li></ul>`
也可能您没有粘贴整个代码,我没有看到服务组件的注入。
您需要在要使用它的组件中导入和注入服务。
在组件构造函数中
import {CommentService} from '../path to service'
constructor(private commentService: CommentService)
{
//you can call the getcomments service here itself or in ngOnInit
this.commentService.getComments().subscribe(data =>
{
console.log(data)
}
} //end constructor
希望您已经测试过您的 commentService 正在通过 console.log
返回数据
试试这个
模板:<ul><li *ngFor="let comment of comments|async"> {{comment.Name}}</li></ul>
comments: Observable<comment[]>;
ngOnInit() {
this.comments = this.getComments();
}
getComments() {
return this.commentService.getComments();
}
我发现你的代码有 2 个问题
1. 你调用 map 没有返回任何值。
2. 您尝试在地图内部设置值而不是订阅,但是一旦它在您的 ngOnInit
中达到订阅,这些值就未定义
I have found a solution of my issue using Zone and promise.
below is the update code of the "comments.component.ts".
by using zone.run(), I am able to bind data with HTML when
"comments.component" is loaded.
Is this a correct way to bind data with HTML if data is coming using api?
import { Component, OnInit, NgZone } from '@angular/core'; //NgZone *
import { Router} from '@angular/router'
import { Comment } from 'comment entity path'
import {CommentService} from 'comment service path'
import { Observable } from 'rxjs/Observable';
import 'rxjs/add/operator/toPromise' // *
@Component({
template: `<ul *ngIf="comments && comments.length > 0">
<li *ngFor="let item of comments"> {{item.Name}}</li>
</ul>`
})
export class CommentComponent implements OnInit {
comments: comment[]=[]; // *
constructor(private router: Router, private commentService: CommentService, private zone: NgZone) {
}
ngOnInit() {
this.zone.run(() => {
this.getComments().toPromise().then((data) => {
this.comments= data || [];
});
})
}
getComments() {
return this.commentService.getComments();
}
}
您可以使用 ChangeDetectorRef class 强制检测组件及其子组件的更改。
您将需要创建类型为 ChangeDetectorRef 的 class 属性,如下所示:
private cdr: ChangeDetectorRef
在 OnInit() 中加载数据后,只需调用 detectChanges() 方法即可手动 运行 更改检测:
this.cdr.detectChanges();
我对 angular2 有同样的问题,从 OnInit/AfterViewInit 调用 API 并且绑定没有在视图中更新(select 下拉数组没有填充在视图中)。
上述方法对我有用,但我仍然不知道根本原因。
Please direct me to the root cause for this issue as I am unable to find one.
Tt 现在是 2022 年了,问题仍然存在 angular 6. 另一种解决方法是使用 setTimeout 函数,它会进行脏检查。
ngOnInit() {
setTimeout(() => {
this.comments = this.getComments();
}, 1000);
}
comment.component.ts:
import { Component, OnInit } from '@angular/core';
import { Router} from '@angular/router'
import { Comment } from 'comment entity path'
import {CommentService} from 'comment service path'
import { Observable } from 'rxjs/Observable';
@Component({
template: ` <ul><li *ngFor="let comment of comments|async"> {{comment.Name}}</li></ul>`
})
export class CommentComponent implements OnInit {
comments: Observable<comment[]>;
constructor(private router: Router, private commentService: CommentService) {
}
ngOnInit() {
this.comments = this.getComments();
}
getComments() {
return this.commentService.getComments();
}
}
comment.service.ts
import { Injectable } from '@angular/core';
import { Headers, Http, Response } from '@angular/http';
import { Comment } from 'comment path here';
import { Observable } from 'rxjs/Rx';
import 'rxjs/add/operator/map';
import 'rxjs/add/operator/catch';
@Injectable()
export class CommentService {
private commentUrl = 'api path'; // URL to web api
constructor(private http: Http) {
}
getComments(): Observable<Comment[]> {
return this.http.get(this.commentUrl).map(
(response) => {
let data = response.text() ? response.json():[{}];
if (data) {
console.log(data);
return data;
}
return data;
});
}
}
在 ngOnInit
方法中,我可以获得评论列表,但问题是该列表未使用 HTML 上的 ngFor
进行绑定。这是因为 HTML 在响应之前呈现。但是在刷新页面时数据会自动绑定。我错过了什么吗?
一种解决方案是仅在您的评论加载后显示您的 ul
,然后强制刷新。所以像:
<ul *ngIf="comments"><li *ngFor="let comment of comments">{{comment.Name}}</li></ul>
所以一旦 comments
被加载,Angular 将强制刷新,并且 ul
将被添加到 DOM,此时它将具有每个评论绑定 li
所需的所有数据。
使用异步管道通过 observable 加载数据。
<li *ngFor="let comment of comments | async">
尝试在 ul 标签中添加 ngFor
<ul *ngFor="let comment of comments"><li > {{comment.Name}}</li></ul>`
or
<ul *ngFor="let comment of (comments|async)"> <li> {{comment.Name}}</li></ul>`
也可能您没有粘贴整个代码,我没有看到服务组件的注入。
您需要在要使用它的组件中导入和注入服务。 在组件构造函数中
import {CommentService} from '../path to service'
constructor(private commentService: CommentService)
{
//you can call the getcomments service here itself or in ngOnInit
this.commentService.getComments().subscribe(data =>
{
console.log(data)
}
} //end constructor
希望您已经测试过您的 commentService 正在通过 console.log
返回数据试试这个
模板:<ul><li *ngFor="let comment of comments|async"> {{comment.Name}}</li></ul>
comments: Observable<comment[]>;
ngOnInit() {
this.comments = this.getComments();
}
getComments() {
return this.commentService.getComments();
}
我发现你的代码有 2 个问题 1. 你调用 map 没有返回任何值。 2. 您尝试在地图内部设置值而不是订阅,但是一旦它在您的 ngOnInit
中达到订阅,这些值就未定义 I have found a solution of my issue using Zone and promise.
below is the update code of the "comments.component.ts".
by using zone.run(), I am able to bind data with HTML when
"comments.component" is loaded.
Is this a correct way to bind data with HTML if data is coming using api?
import { Component, OnInit, NgZone } from '@angular/core'; //NgZone *
import { Router} from '@angular/router'
import { Comment } from 'comment entity path'
import {CommentService} from 'comment service path'
import { Observable } from 'rxjs/Observable';
import 'rxjs/add/operator/toPromise' // *
@Component({
template: `<ul *ngIf="comments && comments.length > 0">
<li *ngFor="let item of comments"> {{item.Name}}</li>
</ul>`
})
export class CommentComponent implements OnInit {
comments: comment[]=[]; // *
constructor(private router: Router, private commentService: CommentService, private zone: NgZone) {
}
ngOnInit() {
this.zone.run(() => {
this.getComments().toPromise().then((data) => {
this.comments= data || [];
});
})
}
getComments() {
return this.commentService.getComments();
}
}
您可以使用 ChangeDetectorRef class 强制检测组件及其子组件的更改。 您将需要创建类型为 ChangeDetectorRef 的 class 属性,如下所示:
private cdr: ChangeDetectorRef
在 OnInit() 中加载数据后,只需调用 detectChanges() 方法即可手动 运行 更改检测:
this.cdr.detectChanges();
我对 angular2 有同样的问题,从 OnInit/AfterViewInit 调用 API 并且绑定没有在视图中更新(select 下拉数组没有填充在视图中)。 上述方法对我有用,但我仍然不知道根本原因。
Please direct me to the root cause for this issue as I am unable to find one.
Tt 现在是 2022 年了,问题仍然存在 angular 6. 另一种解决方法是使用 setTimeout 函数,它会进行脏检查。
ngOnInit() {
setTimeout(() => {
this.comments = this.getComments();
}, 1000);
}