Javascript 在初始加载时使用异步管道时,模板未绑定到observable
我正在使用JSSDK获取服务中的数据。SDK提供了一种从承诺中检索条目并解析这些条目的方法。因为我想使用可观察的,所以我返回承诺作为可观察的,然后从那里转换 在我的主页组件中,我将调用contentfulServiceOnInit,并使用异步管道展开模板中的可观察内容 我的问题:Javascript 在初始加载时使用异步管道时,模板未绑定到observable,javascript,angular,asynchronous,rxjs,contentful,Javascript,Angular,Asynchronous,Rxjs,Contentful,我正在使用JSSDK获取服务中的数据。SDK提供了一种从承诺中检索条目并解析这些条目的方法。因为我想使用可观察的,所以我返回承诺作为可观察的,然后从那里转换 在我的主页组件中,我将调用contentfulServiceOnInit,并使用异步管道展开模板中的可观察内容 我的问题: 加载主组件时,即使服务已成功获取数据,模板也不存在。现在,如果我在页面上与DOM交互(单击,悬停),模板将立即出现。为什么这不仅仅是在页面加载时异步加载?我怎样才能解决这个问题 contentful.service.
加载主组件时,即使服务已成功获取数据,模板也不存在。现在,如果我在页面上与DOM交互(单击,悬停),模板将立即出现。为什么这不仅仅是在页面加载时异步加载?我怎样才能解决这个问题 contentful.service.ts
import { Injectable } from '@angular/core';
import { Observable, Subject } from 'rxjs/Rx';
import { Service } from '../models/service.model';
import * as contentful from 'contentful';
@Injectable()
export class ContentfulService {
client: any;
services: Service[];
service: Service;
constructor() {
this.client = contentful.createClient({
space: SPACE_ID,
accessToken: API_KEY
});
}
loadServiceEntries(): Observable<Service[]> {
let contentType = 'service';
let selectParams = 'fields';
return this.getEntriesByContentType(contentType, selectParams)
.take(1)
.map(entries => {
this.services = [];
let parsedEntries = this.parseEntries(entries);
parsedEntries.items.forEach(entry => {
this.service = entry.fields;
this.services.push(this.service);
});
this.sortAlpha(this.services, 'serviceTitle');
return this.services;
})
.publishReplay(1)
.refCount();
}
parseEntries(data) {
return this.client.parseEntries(data);
}
getEntriesByContentType(contentType, selectParam) {
const subject = new Subject();
this.client.getEntries({
'content_type': contentType,
'select': selectParam
})
.then(
data => {
subject.next(data);
subject.complete();
},
err => {
subject.error(err);
subject.complete();
}
);
return subject.asObservable();
}
sortAlpha(objArray: Array<any>, property: string) {
objArray.sort(function (a, b) {
let textA = a[property].toUpperCase();
let textB = b[property].toUpperCase();
return (textA < textB) ? -1 : (textA > textB) ? 1 : 0;
});
}
}
import { Component, OnInit } from '@angular/core';
import { Observable } from 'rxjs/Rx';
import { ContentfulService } from '../shared/services/contentful.service';
import { Service } from '../shared/models/service.model';
@Component({
selector: 'app-home',
templateUrl: './home.component.html',
styleUrls: ['./home.component.scss']
})
export class HomeComponent implements OnInit {
service: Service;
services: Service[];
services$: Observable<Service[]>;
constructor(
private contentfulService: ContentfulService,
) {
}
ngOnInit() {
this.services$ = this.contentfulService.loadServiceEntries();
this.services$.subscribe(
() => console.log('services loaded'),
console.error
);
};
}
...
<section class="bg-faded">
<div class="container">
<div class="row">
<div class="card-deck">
<div class="col-md-4 mb-4" *ngFor="let service of services$ | async">
<div class="card card-inverse text-center">
<img class="card-img-top img-fluid" [src]="service?.serviceImage?.fields?.file?.url | safeUrl">
<div class="card-block">
<h4 class="card-title">{{service?.serviceTitle}}</h4>
<ul class="list-group list-group-flush">
<li class="list-group-item bg-brand-black"><i class="fa fa-wrench mr-2" aria-hidden="true"></i>Cras justo odio</li>
<li class="list-group-item bg-brand-black"><i class="fa fa-wrench mr-2" aria-hidden="true"></i>Dapibus ac facilisis in</li>
<li class="list-group-item bg-brand-black"><i class="fa fa-wrench mr-2" aria-hidden="true"></i>Vestibulum at eros</li>
</ul>
</div>
<div class="card-footer">
<a href="#" class="btn btn-brand-red">Learn More</a>
</div>
</div>
</div>
</div>
</div>
</div>
</section>
...
从'@angular/core'导入{Injectable};
从'rxjs/Rx'导入{可观察,主题};
从“../models/Service.model”导入{Service};
将*从“contentful”导入为contentful;
@可注射()
导出类内容服务{
客户:任何;
服务:服务[];
服务:服务;
构造函数(){
this.client=contentful.createClient({
space:space\u ID,
accessToken:API_密钥
});
}
loadServiceEntries():可观察{
让contentType='服务';
让selectParams='fields';
返回此.getEntriesByContentType(contentType,selectParams)
.采取(1)
.map(条目=>{
这是服务=[];
让parsedEntries=this.parseEntries(条目);
parsedEntries.items.forEach(条目=>{
this.service=entry.fields;
this.services.push(this.service);
});
this.sortAlpha(this.services,'servicetail');
归还此服务;
})
.publishReplay(1)
.refCount();
}
解析条目(数据){
返回this.client.parseEntries(数据);
}
getEntriesByContentType(contentType,selectParam){
常量主题=新主题();
this.client.getEntries({
“内容类型”:内容类型,
“选择”:selectParam
})
.那么(
数据=>{
主题。下一步(数据);
subject.complete();
},
错误=>{
主体错误(err);
subject.complete();
}
);
返回subject.asObservable();
}
sortAlpha(objArray:Array)
...
听起来满足的承诺在Angular的区域之外解决
通过将NgZone
注入您的服务,您可以确保observable的方法在区域内运行:
import { NgZone } from '@angular/core';
constructor(private zone: NgZone) {
this.client = contentful.createClient({
space: SPACE_ID,
accessToken: API_KEY
});
}
在调用受试者的方法时,通过使用注入区的run
调用:
getEntriesByContentType(contentType, selectParam) {
const subject = new Subject();
this.client.getEntries({
'content_type': contentType,
'select': selectParam
})
.then(
data => {
this.zone.run(() => {
subject.next(data);
subject.complete();
});
},
err => {
this.zone.run(() => {
subject.error(err);
subject.complete();
});
}
);
return subject.asObservable();
}
谢谢@cartant,这绝对是问题所在。我以为这会很简单……我不知道
NgZone
的用例。