Это мое первое подчинение SO, поэтому, если что-то не так или нет в нужном месте, пожалуйста, не стесняйтесь говорить мне.collectionCount не отображает значение в шаблоне/meteor-rxjs в сервисе
Теперь мой вопрос:
Я пытаюсь реализовать услугу в простом приложении к делать на основе the Angular2 meteor-base boilerplate.
Рассмотрим следующий код, где я пытаюсь сделать две вещи:
- Показать кучу списков (< - это работает)
- дисплей количество списков присутствующих с .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();
}
}
Это один, я импортировать в моих app.module.ts и добавить его к поставщикам массива.
Тогда в моих list.component.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:
В моем шаблоне я, например, сделать следующее :
<!-- 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() был, с моей точки зрения, как кто-то делает это как хобби, очевидным, что нужно сделать. К сожалению, никакого эффекта. Насколько я понимаю, это придает 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:
После подписки на Наблюдаемый вернулся из службы и получил е значение, я придаю значение переменной и использовать его так:
<span class="badge badge-accent pull-right">{{ numTodoLists }}</span>
что приводит к
Кроме того, значение обновляется автоматически, как только я добавить новый список - все работает как ожидалось.
Спасибо ТОЧНО и особенно @ghybs, вы потрясающий.
Лучший первый вопрос, который я видел! – chazsolo
@chazsolo Спасибо! Если вам интересно, я обновил свой вопрос с помощью решения, которое работает для меня. – minau87