我正在尝试在Angular 5中构建一个数据服务,它从平面文件中读取数据并将其传递给组件进行显示。该文件位于相对于数据服务的../data-files目录中。
问题是我很难验证服务是否正在向组件提供数据。为了简单起见,我尝试放置console.log(数据);在组件的构造函数中,但到目前为止,我一直无法确定发生了什么。
这是我的数据服务代码:
import { Injectable } from '@angular/core';
import { HttpClient } from '@angular/common/http';
import { Observable } from 'rxjs/Observable';
import { of } from 'rxjs/observable/of';
@Injectable()
export class DataService {
dataUrl = '../data-files/migrations.json';
DATA;
constructor(private http: HttpClient) {};
getData(): Observable<any>{
return this.http.get(this.dataUrl);
};
ngOnInit() {
this.getData();
};
}
这就是我的组件的样子:
import { Component, OnInit, OnChanges, ViewChild, ElementRef, Input, ViewEncapsulation } from '@angular/core';
import * as d3 from 'd3';
import { DataService } from '../services/data.service';
@Component({
selector: 'app-mosaic-view',
templateUrl: './mosaic-view.component.html',
styleUrls: ['./mosaic-view.component.css'],
encapsulation: ViewEncapsulation.None,
// providers: [DataService]
})
export class MosaicViewComponent implements OnInit, OnChanges {
@ViewChild('chart') private chartContainer: ElementRef;
// @Input() private data: Array<any>;
data;
// chart variables go here.
private chart: any;
private width: number;
private height: number;
constructor(private dataService: DataService) {
console.log("mosaic-view constructed..."); // does not print anything.
};
ngOnInit() {
this.getData();
this.createChart();
if(this.data){
this.updateChart();
}
};
ngOnChanges() {
if(this.chart){
this.updateChart();
}
};
getData(): void {
this.data = this.dataService.getData().subscribe(data => this.data = data);
console.log(this.data); // does not print anything.
}
createChart(){
// creates the mosaic viz, build on d3.treemap()
// TODO
};
updateChart(){
// updates the viz when the data changes.
// TODO
};
}
即使直接将它们放在构造函数中,console.log(...)语句也不会打印。
在我的app.component.html文件中,我引用了一个如下所示的选择器:
...
<div id="app-mosaic-view"></div>
...
在linter或控制台中没有显示错误。我试图遵循建立这样一项服务的最佳做法,但有些事情是不对的,我无法准确说出是什么。
非常感谢任何帮助。
编辑:我做了一些建议的更改,现在我遇到了我想要加载的数据文件的404错误。我检查了路径,甚至尝试明确指定无效的路径。知道为什么它找不到文件吗?
新组件:
import { Component, OnInit, OnChanges, ViewChild, ElementRef, Input, ViewEncapsulation } from '@angular/core';
import * as d3 from 'd3';
import { DataService } from '../services/data.service';
@Component({
selector: 'app-mosaic-view',
templateUrl: './mosaic-view.component.html',
styleUrls: ['./mosaic-view.component.css'],
encapsulation: ViewEncapsulation.None,
// providers: [DataService]
})
export class MosaicViewComponent implements OnInit, OnChanges {
@ViewChild('chart') private chartContainer: ElementRef;
componentName: string = 'Mosaic View';
private data: any[];
private errorMessage: string;
// chart variables go here.
private chart: any;
private width: number;
private height: number;
constructor(private dataService: DataService) {
console.log("mosaic-view constructed...");
};
ngOnInit() {
this.getData();
if(this.data){
this.updateChart();
}
};
ngOnChanges() {
if(this.chart){
this.updateChart();
}
};
getData(): void {
this.dataService.getData().subscribe(
(data: any[]) => {
// this.data = data;
this.data = data;
this.createChart(data);
},
(error: any) => this.errorMessage = <any>error
);
console.log(this.data);
}
createChart(data){
// creates the mosaic viz, build on d3.treemap()
// TODO
};
updateChart(){
// updates the viz when the data changes.
// TODO
};
}
新服务:
import { Injectable } from '@angular/core';
import { HttpClient } from '@angular/common/http';
import { Observable } from 'rxjs/Observable';
import { of } from 'rxjs/observable/of';
import {catchError, map, tap } from 'rxjs/operators';
@Injectable()
export class DataService {
dataUrl: string = '../consolidated_cohorts/src/app/data-files/migrations.json';
constructor(private http: HttpClient) {
console.log("data service called...")
this.getData();
};
getData(): Observable<any>{
return this.http.get<any[]>(this.dataUrl)
.pipe(
tap(data => console.log(data)),
// catchError(this.handleError) // TODO
);
};
// private handleError: {
// console.log("there was an error.");
// }
}
404错误: http://localhost:4200/data-files/migrations.json 404(未找到)
答案 0 :(得分:2)
您缺少订阅。 Observable在订阅之前不会执行。在获取数据之后,您想要执行的任何代码都需要进入subscribe方法的回调。
我的代码如下所示:
<强>组件强>
ngOnInit(): void {
this.productService.getProducts().subscribe(
(products: IProduct[]) => {
this.products = products;
this.filterComponent.listFilter =
this.productParameterService.filterBy;
},
(error: any) => this.errorMessage = <any>error
);
}
我将一个函数传递给subscribe方法,该方法将返回的产品存储在一个局部变量(我用于绑定)中,并根据以前保留的任何过滤器设置过滤列表。 (这只是我代码中的一个例子......你的回调中会有不同的代码。)
您的代码可能如下所示:
ngOnInit() {
this.createChart();
this.getData().subscribe(data => this.updateChart());
};
是的!正如Narm所提到的,服务中没有OnInit生命周期钩子。这就是我的服务:
<强>服务强>
import { catchError, tap } from 'rxjs/operators';
getProducts(): Observable<IProduct[]> {
return this.http.get<IProduct[]>(this.productsUrl)
.pipe(
tap(data => console.log(JSON.stringify(data))),
catchError(this.handleError)
);
}
您可以将其缩短为:
getProducts(): Observable<IProduct[]> {
return this.http.get<IProduct[]>(this.productsUrl);
}
我添加了tap
运算符,将结果记录到控制台以进行调试。这是&#34;最佳实践&#34;添加一些异常处理。
答案 1 :(得分:2)
生命周期钩子,如ngOnInit(),可以使用指令和组件。它们不能与其他类型一起使用,例如服务。在您的服务中,您应该删除ngOnInit并将逻辑从它移动到您的构造函数中,如下所示:
constructor(private http: HttpClient) {
this.getData();
};