2017-02-16 4 views
3

これは私の最初の投稿ですので、何かが間違っていたり、適切な場所にない場合は、教えてください。私の質問に今collectionCountがサービスのテンプレート/ meteor-rxjsに値を表示していません

私はthe Angular2 meteor-base boilerplateに基づいて簡単なのto-doアプリケーション内でサービスを実装しようとしています。

  • を備えた本リストの数を表示します -

    • 表示に-Doリストの束(これは作品<):

      は、私は二つのことをやろうとしている次のコードは、考えてみましょう

      0: - .collectionCount()

    todolist.service.ts(<これは動作しません)

    import { Injectable } from '@angular/core'; import { Subscription, Observable } from 'rxjs'; import { MeteorObservable, ObservableCursor } from 'meteor-rxjs'; import { Todolist } from '../../../../../both/models/todolist.model'; import { Todolists } from '../../../../../both/collections/todolists.collection'; @Injectable() export class TodolistService { todolistSubscription: Subscription; todoLists$: Observable<Todolist[]>; numLists$: Observable<number>; constructor() { this.initListSubscription(); } initListSubscription() { if (!this.todolistSubscription) { this.todolistSubscription = MeteorObservable.subscribe("todolists").subscribe(() => { // Code to be executed when the subscription is ready goes here // This one works this.todoLists$ = Todolists.find({}).zone(); this.todoLists$.subscribe((lists) => { console.log(lists); }); // This one doesn't this.numLists$ = Todolists.find({}).collectionCount(); this.numLists$.subscribe((numberOfLists) => { console.log(numberOfLists); }) }); } } getLists(selector?, options?) { // Just in case anyone is wondering what those params are for... // return Todolists.find(selector || {}, options || {}); return this.todoLists$; } getListsCount() { return this.numLists$; } unsubscribeFromLists() { this.todolistSubscription.unsubscribe(); } } 

    この1つは、私は私のapp.module.tsにインポートして、プロバイダアレイに追加します。

    import { Component, OnInit } from '@angular/core'; 
    import { TodolistService } from '../../shared/todolist.service' 
    // + all other relevant imports, e.g. Todolist (the model), Todolists (collection) 
    
    @Component({ 
        selector: 'list-component', 
        template, 
        styles: [style] 
    }) 
    
    export class ListComponent implements OnInit{ 
    
        lists$: Observable<Todolist[]>; 
        numLists$: Observable<number>; 
    
        constructor(private _todolistService: TodolistService){} 
    
        ngOnInit(){ 
        // Again, this one works... 
        this._todolistService.getLists().subscribe((lists) => { 
         console.log(lists); 
        }); 
    
        // ...and this does not 
        this._todolistService.getListsCount().subscribe((number) => { 
         console.log(number); 
        }); 
    
        // This I can also use in my template, see below... 
        this.lists$ = this._todolistService.getLists(); 
    
        // This one I can't 
        this.numLists$ = this._todolistService.getListsCount(); 
        } 
    
    } 
    

    todolist.component.html:例えば、私は次の手順に従ってください私のテンプレートで

    list.component.ts私はそうのようなサービスを利用で次に

    、 :

    <!-- This one works... --> 
    <div *ngFor="let list of lists$ | async">{{list._id}}</div> 
    
    <!-- This one doesn't... --> 
    <span class="badge">{{ numLists$ | async }}</span> 
    

    物事は私が試した: .zoneを添加

    • () -
     getListsCount() { 
         return this.numLists$.zone(); 
         } 
    
    • ような私のサービスに規定された方法オペレータは、)(.zoneの添加であること(これを試みました - initListSubscription()でオペレータ) - サブスクリプションが
    • は私のコンポーネントで同じことをしようとした準備ができたとき、私は物事を行うサービスの方法、私は呼ん
    // with the addition of .zone() 
        this.numLists$ = this._todolistService.getListsCount().zone(); 
    

    .zoneを追加=====

    ()は趣味としてこれを行い、誰か、行うには明白なこととして、私の視点から、でした。残念ながら、何の効果もありません。私が理解から、これはangularsゾーンに起こっasynchronusタスクを添付して、基本的には例えば

    constructor(private _zone: NgZone){} 
    
    ngOnInit(){ 
        this._zone.run(() => { 
        //...do stuff here that's supposed to be executed in angulars zone 
        }) 
    } 
    

    を言うと同じです。

    誰かが私を助けることができますか?私は実際に何が起こっているのかを理解しようとしましたが、私は頭を包むことができません。なぜ、私はその観察可能なリストの実際の数を得ることができません。私は、直接私のコンポーネントでこのすべてを行うことをしたと-DOSに、私は思います私は新しい追加した場合、私は私のリストを自動的に更新したい場合は

    私は思ったんだけどもう一つは

    MeteorObservable.subscribe("todolists").subscribe(() => { 
        // The additional part that's to be executed, each time my data has changed 
        MeteorObservable.autorun().subscribe(() => { 
        this.lists$ = Todolists.find({}).zone(); 
        // with/without .zone() has the same result - that being no result ... 
        this.listCount$ = Todolists.find({}).collectionCount(); 
        }); 
    }); 
    

    ここでは、私のサービス内からどのように反応性を達成するかについての私の頭を覆すことはできません。私はこれを試して、もう一度やりたいリストのために働いていますが、.collectionCount()ではそうではありません。

    ここで正しい方向を指すことができるかどうか本当に感謝します。たぶん私は何かが欠けているかもしれませんが、私はリストを表示することができます(そして、コンポーネント内から何かを実行すると反応的に更新することもできます)ので、理論的にはうまくいくはずです。

    ありがとうございます!

    UPDATE:私は最終的に実用的なソリューションを取得するために管理@ghybsから

    感謝。下に、最終的なコードがあります。

    todolist.service.ts:

    import { Injectable } from '@angular/core'; 
    import { Observable, Subscription, Subject } from 'rxjs'; 
    import { MeteorObservable, ObservableCursor } from 'meteor-rxjs'; 
    
    import { Todolist, Task } from '../../../../../both/models/todolist.model'; 
    import { Todolists } from '../../../../../both/collections/todolists.collection'; 
    
    @Injectable() 
    export class TodolistService { 
    
        todolistSubscription: Subscription; 
        todoLists$: ObservableCursor<Todolist> = Todolists.find({}); 
        numLists$: Observable<number>; 
        numLists: number = 0; 
        subReady: Subject<boolean> = new Subject<boolean>(); 
    
        init(): void { 
        if(!this.todolistSubscription){ 
         this.subReady.startWith(false); 
         this.todolistSubscription =  MeteorObservable.subscribe("todolists").subscribe(() => { 
         this.todoLists$ = Todolists.find({}); 
         this.numLists$ = this.todoLists$.collectionCount(); 
         this.numLists$.subscribe((numberOfLists) => { 
          console.log(numberOfLists) 
         }); 
         this.todoLists$.subscribe(() => { 
          this.subReady.next(true); 
         }); 
         });  
        } 
        } 
    
        isSubscriptionReady(): Subject<boolean> { 
        return this.subReady; 
        } 
    
        getLists(selector?, options?): ObservableCursor<Todolist> { 
        return this.todoLists$; 
        } 
    
        getListsCount(): Observable<number> { 
        return this.numLists$; 
        } 
    
        addList(name: string, description: string): Observable<string> { 
        return MeteorObservable.call<string>("addTodoList", name, description); 
        } 
    
        addTask(listId: string, identifier: string, description: string, priority: number, start: Date, end: Date): Observable<number> { 
        return MeteorObservable.call<number>("addTask", listId, identifier, description, priority, start, end); 
        } 
    
        markTask(listId: string, task: Task, index: number) : Observable<number> { 
        return MeteorObservable.call<number>("markTask", listId, task, index); 
        } 
    
        disposeSubscription() : void { 
        if (this.todolistSubscription) { 
         this.subReady.next(false); 
         this.todolistSubscription.unsubscribe(); 
         this.todolistSubscription = null; 
        } 
        } 
    
    } 
    

    dashboard.component.ts:

    import { Component, OnInit, OnDestroy } from '@angular/core'; 
    import { Router } from '@angular/router'; 
    import { routerTransition } from '../shared/animations' 
    import { Observable, Subject } from 'rxjs'; 
    import { ObservableCursor } from 'meteor-rxjs'; 
    import { Todolist } from '../../../../both/models/todolist.model'; 
    import { TodolistService } from '../shared/services/todolist.service'; 
    
    import template from './dashboard.component.html'; 
    import style from './dashboard.component.scss'; 
    
    @Component({ 
        selector: 'dashboard', 
        template, 
        styles: [style], 
        animations: [routerTransition()] 
    }) 
    
    export class DashboardComponent implements OnInit, OnDestroy { 
    
        todoLists$: ObservableCursor<Todolist>; 
        numTodoLists$: Observable<number>; 
        numTodoLists: number = 0; 
    
        constructor(private _router: Router, private todolistService: TodolistService) {} 
    
        ngOnInit() { 
        this.todolistService.init(); 
        this.todolistService.isSubscriptionReady().subscribe((isReady) => { 
         if(isReady){ 
         this.todolistService.getListsCount().subscribe((numTodoLists) => { 
          this.numTodoLists = numTodoLists; 
         });    
         } 
        }); 
        } 
    
        sideNavShown: boolean = true; 
        toggleSideNav() { 
        this.sideNavShown = !this.sideNavShown; 
        } 
    
        ngOnDestroy() { 
        this.todolistService.disposeSubscription(); 
        } 
    
    } 
    

    dashboard.component.html:

    に加入した後にサービスから復帰し、受信e値は、私は変数に値を代入し、そのようにそれを使用します。

    またthe number of lists displayed

    になり

    <span class="badge badge-accent pull-right">{{ numTodoLists }}</span> 
    

    は、値が自動的にすぐに私は新しいを追加すると、更新され、リスト - すべて期待どおりに動作します。

    ありがとうございます。特に@ghybs、あなたは素晴らしいです。

  • +0

    私が見た最初の質問 – chazsolo

    +0

    @chazsoloありがとう!興味があれば、私のために働いているソリューションで質問を更新しました。 – minau87

    答えて

    1

    ObservableCursormyCollection.find()から返されたもの)を有効にする前に購読する必要があることに気付きました。私たちは、それがコールドであると考えています。

    単純な状況(AsyncPipeを介してテンプレートにカーソルを直接渡すなど)では、Angularはサブスクリプションを(asyncパイププロセスの一部として)実行します。

    あなたがそれにcollectionCount()を適用する前に、あなたがそれを購読することができますようにだからあなたの場合には、あなたは、単に、find()によって返された中間オブジェクトへの参照を取得する必要があります。

    const cursor = Todolists.find({}); 
    this.numLists$ = cursor.collectionCount(); 
    this.numLists$.subscribe((numberOfLists) => { 
        console.log(numberOfLists); 
    }); 
    cursor.subscribe(); // The subscribe that makes it work. 
    

    次に、あなたがすることができますテンプレートにAsyncPipeを通じてnumLists$を使用するか:

    {{ numLists$ | async}}

    それとも、あなたが以内に割り当てる簡単な中間プレースホルダを使用することができます{{numLists}}

    反応性については、あなただけの観測を再割り当て機能をラップするMeteorObservable.autorun()を必要としません:AsyncPipeが正しく観測を使用し、それに応じて反応する

    private numLists: number; 
    
    // ... 
    this.numLists$.subscribe((numberOfLists) => { 
        this.numLists = numberOfLists; 
    }); 
    

    とテンプレートで。

    findOne()の場合は、Observableではなくオブジェクトが直接返される状況が異なります。

    +0

    ありがとうございます、今はすべて期待どおりに動作しています。私は実際の解決策で質問を更新しました。また、私はこれが公式のチュートリアルでカバーされていないトピックであることに気がついたので、私は再びタイトルの "サービス"を述べました。たぶんそれは将来の誰かにとって役に立ちます。 – minau87

    関連する問題