javascript - Kan inte sätta prenumererat observerbart i samling som en sträng
Jag är ganska ny på Typescript och Javascript, och jag har riktigt svårt att förstå hur samlingar och filinmatning/utmatning fungerar. Jag försöker hämta data från en JSON-fil, vilket jag lyckas med, men när jag lägger in det i en samling har samlingen inte datan.
Här är koden:
I min tjänsteklass:
private configuration = "../../assets/Configurations/testConfiguration.json";
constructor(private http: HttpClient) {}
getBlogs(blog: string): Observable<IBlogPost[]> {
return this.http.get<IBlogPost[]>(blog);
}
getConfigurations() {
var configurationsData = [];
this.http.get(this.configuration).subscribe(data => {
configurationsData.push(data);
console.log(data);
// This will work and will print all the paths
});
//This will not work and will not print them, like if the collection is empty
configurationsData.forEach(x => console.log(x));
return configurationsData;
}
Var jag får min serviceklass injicerad:
blogs: IBlogPost[] = [];
private blogsPaths: string[] = [];
errorMessage = "";
constructor(private appUtilityService: AppUtilityServices) {}
ngOnInit() {
//This will not work, blogsPaths will not received the full collection as it should
this.blogsPaths = this.appUtilityService.getConfigurations();
this.blogsPaths.forEach(blogPath =>
this.appUtilityService.getBlogs(blogPath).subscribe(
b =>
b.forEach(blog => {
this.blogs.push(blog);
}),
error => (this.errorMessage = <any>error)
)
);
}
testConfiguration.json:
[
"../../assets/BlogPosts/testBlog1.json",
"../../assets/BlogPosts/testBlog2.json"
]
Bonus om du inkluderar en bra handledning om hur samlingar fungerar i JavaScript och hur man returnerar dem på rätt sätt
Svar #1
Visar sig vara detta, ja verkligen...
Här gjorde jag det fint:
OnInit :
this.appUtilityService.getConfigurations().subscribe(
b =>
b.forEach(x => {
this.appUtilityService.getBlogs(x).subscribe(
b =>
b.forEach(blog => {
this.blogs.push(blog);
}),
error => (this.errorMessage = <any>error)
);
}),
error => (this.errorMessage = <any>error)
);
AppUtilityService:
getBlogs(blog: string): Observable<IBlogPost[]> {
return this.http.get<IBlogPost[]>(blog);
}
getConfigurations(): Observable<string[]> {
return this.http.get<string[]>(this.configuration);
}
Gör det riktigt fint:
ngOnInit() {
this.initializeBlog();
}
private initializeBlog(): void {
this.appUtilityService.getConfigurations().subscribe(
b =>
b.forEach(x => {
this.appUtilityService.getBlogs(x).subscribe(
b =>
b.forEach(blog => {
this.blogs.push(blog);
}),
error => (this.errorMessage = <any>error)
);
}),
error => (this.errorMessage = <any>error)
);
}
Svar #2
Inuti getConfigurations anropar du en asynkron HTTP-förfrågan. Så det är normalt att configurationsData är tomt utanför subscribe-metoden.
Här använder jag kraften i RxJS för att förenkla koden och undvika att använda Array.push och nästlade subscribe().
1) Grundläggande asynkron servicemetod för att hämta data
Så getConfigurations bör returnera ett Observable:
getConfigurations(): Observable<string[]> {
return this.http.get<string[]>(this.configuration);
}
Och också getBlogs bör returnera en Observable:
getBlogs(blogsPath: string): Observable<BlogPost[]> {
return this.http.get<BlogPost[]>(blogsPath);
}
Här, för att respektera Angulars bästa praxis, tar jag bort I i början av varje gränssnitt, så BlogPost.
2) Här är magin med RxJS
Sedan har du en annan metod inuti din tjänst för att hämta en Observable av blogginlägg, som bör se ut så här:
getBlogPosts(): Observable<BlogPost[]> {
return this.getConfigurations().pipe(
mergeAll(),
concatMap(blogsPath => this.getBlogs(blogsPath)),
concatAll(),
toArray()
)
}
Vilket betyder, hämta alla samlingar av bloggvärdar, för varje array av vägar, för varje väg, hämta blogginlägg, och sedan returnera en unik array av alla inlägg.
Till sist, inuti din komponent, kallar du getBlogPosts med en prenumeration:
ngOnInit() {
this.service.getBlogPosts().subscribe(blogs => {
...do something with your blogs array.
});
}
eller ännu bättre med async-pipe inne i din mall:
.ts-fil:
blogs$: Observable<BlogPost[]>;
...
this.blogs$ = this.appService.getBlogPosts();
.html-fil:
<ul *ngIf="blogs$ | async as blogs">
<li *ngFor="let blog of blogs">
#{{ blog.id }} - {{ blog.title }}
</li>
</ul>
Kolla in min fullständiga demonstration av detta RxJS-alternativ på Stackbliz.
Rekommenderad läsning på Medium av Tomas Trajan
