2016-12-28 15 views
1

それが動作するはずのようにこれは私には見えますが、私は、テンプレートのエラーを取得:Cannot find a differ supporting object '[object Object]' of type 'object'. NgFor only supports binding to Iterables such as Arrays.ngForとAsyncPipeについて何が欠けていますか?

テンプレート:

<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> 

コンポーネント:

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)) 
    } 
} 

サービス:

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) 
} 

置き換えコード(th eコンポーネント)では、すべて動作しますが、サブスクリプションの登録を解除する必要があります。私はこのようにしているように感じますが、私のブラウザは同意しません。

Observableで非同期がどのように機能するのか私が誤解していることは何ですか?

+0

を使用すると、フィルターなしでそれを試してみてくださいことはできますか? – echonax

+0

mergeAll()操作を削除してみます。 – Avi

+0

mergeAll()はここで間違いです。 Observable を返す必要があり、非同期フィルタが機能します。しかし、私はまた、以下の答えに投稿したものに近づくようにサービスを改作するつもりです。 – Stuart

答えて

0

「私は何を誤解していますか?あまりにも、あまりにも。

最も基本的なのは、より反応性の高いスタイルのプログラミングをしようとすると、サービスの役割を理解することです。パススルーとして機能する以上のことをしなければなりません。

Cory Rylanによるthis postの読書に基づいて、私のサービスではapiからのデータを全く異なる方法で管理する必要があるという結論に至りました。最後までの概要セクションは、特に読む価値があります。

私は元の投稿でサービスを修正していませんが、私はCRUDdyサービスに使う良いパターンだと思います。このサービスには、自分のコンポーネントが購読するデータストアがあります。そのアクションはそのデータストアを変更し、観察可能なものの奇跡によって、それらのアクションの結果ストアが変更されたときに自動的に更新されます。

あなたが管理しているものは何でもオブジェクトに「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); 
      }); 
    } 
} 
関連する問題