Angular 2 Meteor doesn't fetch data until click

I trying to make a similar app for learning after I took the tutorial, The problem is in the first visit or when I reload the page, everything is ok but when I came from the login page or register page using router navigation (this.router.navigate([‘/’])) then the data didn’t load up until I click somewhere, and I mean do something on the webpage and the data will show up.

task-list.component.ts

import { Component, OnInit, OnDestroy } from '@angular/core';
import { Observable } from 'rxjs/Observable';
import { Subject } from 'rxjs/Subject';
import { Subscription } from 'rxjs/Subscription';
import { MeteorObservable } from 'meteor-rxjs';
import { InjectUser } from "angular2-meteor-accounts-ui";
import { PaginationService } from 'ng2-pagination';
import { Counts } from 'meteor/tmeasday:publish-counts';

import 'rxjs/add/operator/combineLatest';

import { Tasks } from '../../../../both/collections/tasks.collection';
import { Task } from '../../../../both/models/task.model';

import template from './tasks-list.component.html';
import style from './tasks-list.component.scss';

interface Pagination {
    limit: number;
    skip: number;
}

interface Options extends Pagination {
  [key: string]: any
}

@Component({
    selector: 'tasks-list',
    template,
    styles: [style]
})
@InjectUser('user')
export class TasksListComponent {
    tasks: Observable<Task[]>;
    user: Meteor.User;
    pageSize: Subject<number> = new Subject<number>();
    curPage: Subject<number> = new Subject<number>();
    createdAtOrder: Subject<number> = new Subject<number>();
    tasksSize: number = 0;
    name: Subject<string> = new Subject<string>();
    autorunSub: Subscription;
    optionsSub: Subscription;
    tasksSub: Subscription;

    constructor(
        private paginationService: PaginationService
    ) {}

    ngOnInit() {
        this.optionsSub = Observable.combineLatest(
            this.pageSize,
            this.curPage,
            this.createdAtOrder,
            this.name
        ).subscribe(([pageSize, curPage, createdAtOrder, name]) => {
            const options: Options = {
                limit: pageSize as number,
                skip: ((curPage as number) - 1) * (pageSize as number),
                sort: { createdAt: createdAtOrder as number }
            };

            this.paginationService.setCurrentPage(this.paginationService.defaultId(),curPage as number);

            if(this.tasksSub) {
                this.tasksSub.unsubscribe();
            }

            this.tasksSub = MeteorObservable.subscribe('tasks', options, name).subscribe(() => {
                this.tasks = Tasks.find({}, {
                    sort: {
                        createdAt: createdAtOrder
                    }
                }).zone();
            });
        });

        this.paginationService.register({
            id: this.paginationService.defaultId(),
            itemsPerPage: 10,
            currentPage: 1,
            totalItems: this.tasksSize
        });

        this.pageSize.next(10);
        this.curPage.next(1);
        this.createdAtOrder.next(-1);
        this.name.next('');

        this.autorunSub = MeteorObservable.autorun().subscribe(() => {
            this.tasksSize = Counts.get('numberOfTasks');
            this.paginationService.setTotalItems(this.paginationService.defaultId(), this.tasksSize);
        })
    }

    onPageChanged(page: number): void {
        this.curPage.next(page);
    }

    isOwner(task: Task) {
        return this.user && this.user._id === task.owner;
    }

    isDone(task: Task) {
        return task.done === true;
    }

    removeTask(task: Task) {
        Tasks.remove(task._id);
    }

    changeTaskState(task: Task) {
        if(this.user && this.user._id === task.owner){
            Tasks.update(task._id, {$set: {done: !task.done}});
        } else {
            alert('You are not the owner of this task!');
            return;
        }
    }

    search(value: string): void {
        this.curPage.next(1);
        this.name.next(value);
    }

    changeSortOrder(nameOrder: string): void {
        this.createdAtOrder.next(parseInt(nameOrder));
    }

    ngOnDestroy(): void {
        this.tasksSub.unsubscribe();
        this.optionsSub.unsubscribe();
        this.autorunSub.unsubscribe();
    }
}

login.component.ts

import {Component, OnInit, NgZone} from '@angular/core';
import { FormBuilder, FormGroup, Validators } from '@angular/forms';
import { Router } from '@angular/router';
import { Meteor } from 'meteor/meteor';
import { InjectUser } from "angular2-meteor-accounts-ui";

import template from './login.component.html';
import style from './login.component.scss';

@Component({
    selector: 'login',
    template,
    styles: [style]
})
@InjectUser('user')
export class LoginComponent implements OnInit {
    user: Meteor.User;
    loginForm: FormGroup;
    errorMessage: string;

    constructor(
        private router: Router,
        private zone: NgZone,
        private formbuilder: FormBuilder
    ) {}

    ngOnInit() {
        // if(this.user) {
        //     this.router.navigate(['/']);
        // }

        this.loginForm = this.formbuilder.group({
            email: ['', Validators.required],
            password: ['', Validators.required]
        });

        this.errorMessage = '';
    }

    doLogin(): void {
        if(this.loginForm.valid) {
            Meteor.loginWithPassword(this.loginForm.value.email, this.loginForm.value.password, (err) => {
                if(err) {
                    this.zone.run(() => {
                        this.errorMessage = err;
                    })
                } else {
                    this.router.navigate(['/']);
                }
            })
        }
    }
}

And the task-list.component.hml

<div>
    <div class="row"><tasks-form></tasks-form></div>

    <div id="search-box" class="row">
        <div class="col-md-10 offset-md-1">
            <input type="text" class="form-control" #searchText placeholder="Search task" (keyup)="search(searchText.value)">
        </div>
    </div>

    <div id="tasks-list">

        <h1 class="title-text">Tasks:</h1>

        <div class="row">
            <div class="col-md-2">
                <div class="form-group">
                    <label>Sort by date: </label>
                    <select class="form-control" #sort (change)="changeSortOrder(sort.value)">
                        <option value="-1" selected>Descending</option>
                        <option value="1">Ascending</option>
                    </select>
                </div>
            </div>
        </div>

        <div class="row">
            <div class="col-md-6" *ngFor="let task of tasks | async">
                <div class="card">
                    <div class="card-block">
                        <a class="card-title" [routerLink]="['/task', task._id]"><h4>{{task.name}}</h4></a>
                        <p class="card-text">{{task.description}}</p>
                        <p class="card-text"><small class="text-muted">Last updated 3 mins ago</small></p>
                    </div>
                    <div class="card-block">
                        <button class="btn"
                            [ngClass]="isDone(task) ? 'btn-success' : 'btn-warning'"
                            (click)="changeTaskState(task)"
                            [disabled]="!isOwner(task)">
                            {{task | doneButton}}
                        </button>
                        <button *ngIf="isOwner(task)" class="btn btn-danger delete-button" (click)="removeTask(task)">
                            <i class="fa fa-trash" aria-hidden="true"></i>
                        </button>
                    </div>
                </div>
            </div>
        </div>

        <div id="pagination">
            <pagination-controls
                (pageChange)="onPageChanged($event)">
            </pagination-controls>
        </div>
    </div>
</div>

here is the gif that show the error, notice that then data will only show up when I click somewhere in the page

Please help me with this problem, thank you.

You can look for the project here, if someone have time, please help me with this, this error is very weird…
https://github.com/lednhatkhanh/simple-todos

Update: I try to stop meteor and then click the page, the data still shows up, so I think it’s a problem with some packages, I’ve just updated to meteor 1.4.2.1 thought.

package.json

{
  "name": "angular2-meteor-base",
  "private": true,
  "scripts": {
    "start": "meteor run",
    "start:prod": "meteor run --production",
    "build": "meteor build ./build/",
    "clear": "meteor reset",
    "meteor:update": "meteor update --all-packages",
    "test": "meteor test --driver-package practicalmeteor:mocha",
    "test:ci": "meteor test --once --driver-package dispatch:mocha-phantomjs"
  },
  "devDependencies": {
    "@types/chai": "^3.4.34",
    "@types/mocha": "^2.2.32",
    "chai": "3.5.0",
    "chai-spies": "0.7.1"
  },
  "dependencies": {
    "@angular/common": "2.1.2",
    "@angular/compiler": "2.1.2",
    "@angular/core": "2.1.2",
    "@angular/forms": "2.1.2",
    "@angular/http": "2.1.2",
    "@angular/platform-browser": "2.1.2",
    "@angular/platform-browser-dynamic": "2.1.2",
    "@angular/router": "3.1.2",
    "@ng-bootstrap/ng-bootstrap": "^1.0.0-alpha.11",
    "@types/node": "6.0.46",
    "angular2-meteor": "0.7.0",
    "angular2-meteor-accounts-ui": "^1.0.0",
    "angular2-meteor-polyfills": "0.1.1",
    "angular2-meteor-tests-polyfills": "0.0.2",
    "babel-runtime": "^6.18.0",
    "bcrypt": "^0.8.7",
    "bootstrap": "^4.0.0-alpha.5",
    "gm": "1.23.0",
    "meteor-node-stubs": "0.2.3",
    "meteor-rxjs": "^0.4.3",
    "meteor-typings": "1.3.1",
    "ng2-pagination": "1.0.0",
    "reflect-metadata": "0.1.8",
    "rxjs": "5.0.0-beta.12",
    "spawn-sync": "1.0.15",
    "try-thread-sleep": "1.0.0",
    "zone.js": "0.6.26"
  }
}

Meteor packages

accounts-base@1.2.14
accounts-password@1.3.2
allow-deny@1.0.5
angular2-compilers@0.6.6
anti:fake@0.4.1
autoupdate@1.3.12
babel-compiler@6.13.0
babel-runtime@1.0.0
barbatus:css-compiler@0.3.5_1
barbatus:scss-compiler@3.8.2
barbatus:typescript@0.5.2
barbatus:typescript-compiler@0.8.4
barbatus:typescript-runtime@0.1.2
base64@1.0.10
binary-heap@1.0.10
blaze@2.2.0
blaze-tools@1.0.10
boilerplate-generator@1.0.11
caching-compiler@1.1.9
caching-html-compiler@1.0.7
callback-hook@1.0.10
check@1.2.4
coffeescript@1.11.1_3
ddp@1.2.5
ddp-client@1.3.2
ddp-common@1.2.8
ddp-rate-limiter@1.0.6
ddp-server@1.3.12
deps@1.0.12
diff-sequence@1.0.7
dispatch:mocha-phantomjs@0.1.7
dispatch:phantomjs-tests@0.0.5
ecmascript@0.6.0
ecmascript-runtime@0.3.15
ejson@1.0.13
email@1.1.18
es5-shim@4.6.15
fastclick@1.0.13
geojson-utils@1.0.10
hot-code-push@1.0.4
html-tools@1.0.11
htmljs@1.0.11
http@1.2.10
hwillson:stub-collections@1.0.2
id-map@1.0.9
jquery@1.11.10
launch-screen@1.1.0
livedata@1.0.18
localstorage@1.0.12
logging@1.1.16
meteor@1.6.0
meteor-base@1.0.4
minifier-css@1.2.15
minifier-js@1.2.15
minimongo@1.0.18
mobile-experience@1.0.4
mobile-status-bar@1.0.13
modules@0.7.7
modules-runtime@0.7.7
mongo@1.1.14
mongo-id@1.0.6
npm-bcrypt@0.9.2
npm-mongo@2.2.11_2
observe-sequence@1.0.14
ordered-dict@1.0.9
practicalmeteor:chai@2.1.0_1
practicalmeteor:loglevel@1.2.0_2
practicalmeteor:mocha@2.4.5_6
practicalmeteor:mocha-core@1.0.1
practicalmeteor:sinon@1.14.1_2
promise@0.8.8
random@1.0.10
rate-limit@1.0.6
reactive-var@1.0.11
reload@1.1.11
retry@1.0.9
routepolicy@1.0.12
service-configuration@1.0.11
sha@1.0.9
shell-server@0.2.1
spacebars@1.0.13
spacebars-compiler@1.0.13
srp@1.0.10
standard-minifier-css@1.3.2
standard-minifier-js@1.2.1
templating@1.2.15
templating-compiler@1.2.15
templating-runtime@1.2.15
templating-tools@1.0.5
tmeasday:publish-counts@0.8.0
tmeasday:test-reporter-helpers@0.2.1
tracker@1.1.1
ui@1.0.12
underscore@1.0.10
urigo:static-html-compiler@0.1.8
url@1.0.11
webapp@1.3.12
webapp-hashing@1.0.9
xolvio:cleaner@0.3.1

Update 2: The problem only happens when I use navigate, the location.goback still work without problem.

@Urigo If you have time, can you take a look at this? Thank you.

Facing the same problem. Did you make any progress?

Can you post a github repo that we can clone and reproduce?

Here is the github repo.
skype me “gofaizmh” if you need any info

What are the steps to reproduce and expected behavior?
meteor_observable seems to be working (data shows up after navigation).
Please advise.

The data doesnt show up when you click on the below
<button (click)=“accounts_package()”>Using meteor accounts_package
<button (click)=“meteor_methods()”>Using meteor Methods

Are you sure this works for you?

Steps to reproduce: Reload the page.

And you can reproduce the error in the official meteor-angular tutorial too.

  • After step 6, when you are at the party detail route, try to refresh the page: everything disappear, I created an issue for it here
  • After step 9: logout, copy a party link and paste it into a new tab (logged out), it shows a blank page.

I have posted the solution in my github

1 Like

Hi neolto,

Appreciate you posting the solution. Would you mind describing what’s going on here for us new to the Angular2/Meteor community?

Thanks!