Angular 关于ngFor和AsyncPipe,我遗漏了什么?

Angular 关于ngFor和AsyncPipe,我遗漏了什么?,angular,observable,Angular,Observable,在我看来,它应该可以工作,但我遇到了一个模板错误:找不到类型为“object”的不同支持对象“[object object]”。NgFor仅支持绑定到数组之类的可重用项。 模板: <div class="block-header"> <h2>{{ policyName }}</h2> </div> <div *ngFor="let p of policies | async" class="card event-card">

在我看来,它应该可以工作,但我遇到了一个模板错误:
找不到类型为“object”的不同支持对象“[object object]”。NgFor仅支持绑定到数组之类的可重用项。

模板:

<div class="block-header">
    <h2>{{ policyName }}</h2>
</div>
<div *ngFor="let p of policies | async" class="card event-card">
    <div class="card-header">
        <h2>{{ p.title }}</h2>
    </div>
    <div class="card-body card-padding">
        <div [markdown]="p.description"></div>
    </div>
</div>

{{policyName}}
{{p.title}}
组成部分:

export class PoliciesComponent implements OnInit {

  name: string = 'policies';
  //public policies: Policy[];
  public policies: Observable<Policy>;

  constructor(
    private policyService: PolicyService,
    private route: ActivatedRoute) { }

  ngOnInit(): void {
    // this.route.params is an observable of the child (category) routes under /policies
    this.route.params.subscribe((p: Params) => this.loadPolicies(p['category']))
  }

  loadPolicies(category: string): void {
    let policyCategory = PolicyCategory.ClubPolicy;
    if (category === 'rules') {
      policyCategory = PolicyCategory.LocalRule;
    } else if (category === 'handicaps') {
      policyCategory = PolicyCategory.Handicaps;
    }
    this.policies = this.policyService.loadPolicies(policyCategory);
    // this.policies = [];
    // this.policyService.loadPolicies(policyCategory).subscribe(p => this.policies.push(p))
  }
}
导出类策略组件实现OnInit{
名称:string='policies';
//公共政策:政策[];
公共政策:可见;
建造师(
私人保单服务:保单服务,
专用路由:ActivatedRoute){}
ngOnInit():void{
//this.route.params是/policies下的子(类别)路由的可观察项
this.route.params.subscribe((p:params)=>this.loadPolicys(p['category']))
}
LoadPolicys(类别:字符串):无效{
让policyCategory=policyCategory.ClubPolicy;
如果(类别==‘规则’){
policyCategory=policyCategory.LocalRule;
}否则,如果(类别==‘障碍’){
保单类别=保单类别。残障;
}
this.policies=this.policyService.LoadPolicys(policyCategory);
//这是1.policies=[];
//this.policyService.LoadPolicys(policyCategory.subscribe)(p=>this.Policys.push(p))
}
}
服务:

loadPolicies(category: PolicyCategory): Observable<Policy> {
    return this.dataService.getApiRequest('policies')
        .mergeAll() // turn Observable<any> where any=collection into Observable
        .map((p: any) => new Policy().fromJson(p))
        .filter((policy: Policy) => policy.category === category)
}
LoadPolicys(类别:PolicyCategory):可观察{
返回此.dataService.getApiRequest('策略')
.mergeAll()//将Observable where any=集合转换为Observable
.map((p:any)=>newpolicy().fromJson(p))
.filter((策略:策略)=>policy.category==category)
}
有了替换代码(在组件的注释中),一切都正常,但我必须取消订阅。我觉得我做得对,但我的浏览器不同意


关于异步如何与可观察对象一起工作,我有什么误解?

问题“我有什么误解?”的答案是,太多了

我认为,最基本的是,在尝试执行更被动的编程风格时,理解服务的角色。它应该做的不仅仅是作为一个通道

根据Cory Rylan的阅读,我得出结论,我的服务应该以完全不同的方式管理来自api的数据。最后的概述部分特别值得一读

因此,虽然我没有在最初的帖子中修改服务,但我确实有一个我认为用于粗糙服务的好模式。该服务有一个我的组件订阅的数据存储。这些动作会使数据存储发生变化,随着可观测数据的奇迹出现,当这些动作导致存储发生变化时,这些动作会自动更新

将“ProfilerJob”替换为您正在管理的任何对象:

@Injectable()
export class ProfilerJobService {

    private resource: string = 'profile';

    private _jobs: BehaviorSubject<ProfilerJob[]>;
    private store: {
        items: ProfilerJob[]
    };

    constructor(private dataService: DataService) {
        this.store = {
            items: []
        };
        this._jobs = <BehaviorSubject<ProfilerJob[]>>new BehaviorSubject([]);
    }

    get jobs(): Observable<ProfilerJob[]> {
        return this._jobs.asObservable();
    }

    selectJob(id: string): Observable<ProfilerJob> {
        if (id === 'new') {
            return Observable.of(new ProfilerJob());
        }
        return this._jobs.map(jobs => {
            let job = jobs.find(item => item.id === id);
            return _.clone(job);
        });
    }

    loadJobs(filter: JobFilter = null): void {
        let url = this.resource;
        let params: any;
        if (filter) {
            url = url + '/search';
            params = filter.toSearchApi();
        }
        this.dataService.getData(url, params).subscribe(data => {
            this.store.items.length = 0;
            data.forEach((d: any) => this.store.items.push(new ProfilerJob().fromJson(d)));
            this._jobs.next(_.cloneDeep(this.store).items);
        });
    }

    loadJob(id: string): void {
        this.dataService.getData(`${this.resource}/${id}`).subscribe(json => {
            let found = false;
            this.store.items.forEach((item, index) => {
                if (item.id === json.id) {
                    this.store.items[index] = new ProfilerJob().fromJson(json);
                    found = true;
                }
            });
            if (!found) {
                this.store.items.push(new ProfilerJob().fromJson(json));
            }
            this._jobs.next(_.cloneDeep(this.store).items);
        });
    }

    addJob(job: ProfilerJob): Observable<void> {
        return this.dataService.postData(this.resource, job.toJson())
            .do((json: any) => {
                this.loadJob(json.id);
            });
    }

    updateJob(job: ProfilerJob): Observable<void> {
        return this.dataService.putData(`${this.resource}/${job.id}`, job.toJson())
            .do(() => {
                this.loadJob(job.id);
            });
    }

    deleteJob(job: ProfilerJob): Observable<void> {
        return this.dataService.deleteData(`${this.resource}/${job.id}`)
            .do(() => {
                let idx = this.store.items.findIndex(j => j.id === job.id);
                this.store.items.splice(idx, 1);
                this._jobs.next(_.cloneDeep(this.store).items);
            });
    }
}
@Injectable()
导出类ProfilerJobService{
私有资源:字符串='profile';
私人职业:行为主体;
私人店铺:{
项目:ProfilerJob[]
};
构造函数(专用数据服务:数据服务){
此存储={
项目:[]
};
这。_jobs=新行为主体([]);
}
获取作业():可观察{
返回此项。_jobs.asObservable();
}
selectJob(id:string):可观察{
如果(id=='new'){
返回可观测的(新ProfilerJob());
}
返回此。\u jobs.map(jobs=>{
让job=jobs.find(item=>item.id==id);
返回克隆(作业);
});
}
loadJobs(筛选器:JobFilter=null):无效{
让url=this.resource;
让params:任何;
如果(过滤器){
url=url+'/search';
params=filter.toSearchApi();
}
this.dataService.getData(url,参数).subscribe(数据=>{
this.store.items.length=0;
data.forEach((d:any)=>this.store.items.push(newprofilerjob().fromJson(d));
this.\u jobs.next(\u.cloneDeep(this.store).items);
});
}
loadJob(id:字符串):无效{
this.dataService.getData(`${this.resource}/${id}').subscribe(json=>{
让发现=错误;
this.store.items.forEach((项,索引)=>{
if(item.id==json.id){
this.store.items[index]=new ProfilerJob().fromJson(json);
发现=真;
}
});
如果(!找到){
this.store.items.push(新ProfilerJob().fromJson(json));
}
this.\u jobs.next(\u.cloneDeep(this.store).items);
});
}
addJob(作业:ProfilerJob):可观察{
返回this.dataService.postData(this.resource,job.toJson())
.do((json:any)=>{
this.loadJob(json.id);
});
}
updateJob(作业:ProfilerJob):可观察{
返回this.dataService.putData(`${this.resource}/${job.id}`,job.toJson())
.do(()=>{
this.loadJob(job.id);
});
}
deleteJob(作业:ProfilerJob):可观察{
返回this.dataService.deleteData(`${this.resource}/${job.id}`)
.do(()=>{
让idx=this.store.items.findIndex(j=>j.id==job.id);
此.store.items.splice(idx,1);
this.\u jobs.next(\u.cloneDeep(this.store).items);
});
}
}

对于“我误解了什么?”这个问题的答案是,太多了

我认为,最基本的是,在尝试执行更被动的编程风格时,理解服务的角色。它应该做的不仅仅是作为一个通道

根据Cory Rylan的阅读,我得出结论,我的服务应该以完全不同的方式管理来自api的数据。最后的概述部分特别值得一读

因此,虽然我没有在最初的帖子中修改服务,但我确实有一个我认为用于粗糙服务的好模式。该服务具有数据存储