1

I am using angular2-meteor, I already use pure: false. But the pipe sometimes run, sometimes not. See my comments in the code for details of the problem.

Thanks

<div *ngFor="#user of (users|orderByStatus)">
    {{user.status.online}}
</div>


users:Mongo.Cursor<Meteor.User>;
ngOnInit()
{
    this.subscribe('users', () => {
        this.autorun(() => {
            this.users = Meteor.users.find();
        });
    }, true);
}

import {Pipe} from 'angular2/core';

@Pipe({
    name: 'orderByStatus',
    pure: false
})
export class OrderByStatusPipe {
    transform(usersCursor:Mongo.Cursor<Meteor.User>):Array<Meteor.User> {
        console.log("OrderByStatusPipe runs");

        // (1) If I only do these two lines, the change of other users' status can show on the screen immediately. 
        // let users = usersCursor.fetch();
        // return users;

        // (2) If sort users by status, the page sometimes updates, sometimes not when user status change.
        //  If not update automatically, I click that part of screen, it will update then.
        let users:Array<Meteor.User> = usersCursor.fetch();
        users.sort((a, b) => {
            return (a.status.online === b.status.online) ? 0 : (a.status.online ? -1 : 1);
        });
        return users;
    }
}
Hongbo Miao
  • 45,290
  • 60
  • 174
  • 267

2 Answers2

2

UPDATE: The bug seems fixed.

I think the problem is related with angular2-meteor.

At last I found a working way using sort in when you try to get data from Mongo. So not using sort pipe any more.

But you cannot use users:Mongo.Cursor<Meteor.User> with *ngFor, need fetch() first and use Array<Meteor.User>, otherwise it will show this error when the order of list changes:

Cannot read property 'status' of undefined

But then the list won't update automatically in UI. So you need use NgZone.

So the final working code is like this:

<div *ngFor="#user of users)">
    {{user.status.online}}
</div>


users:Array<Meteor.User>;  // here cannot use users:Mongo.Cursor<Meteor.User>
constructor(private _ngZone:NgZone) {}
ngOnInit()
{
    this.subscribe('users', () => {
        this.autorun(() => {
            this._ngZone.run(() => {
                this.users = Meteor.users.find().fetch();
            });
        });
    }, true);
}
Hongbo Miao
  • 45,290
  • 60
  • 174
  • 267
0

I don't know exactly what is behind the calls Meteor.users.find() and usersCursor.fetch() but I think the retrieval of your users should be done outside the filter itself. I guess that one part is done in the filter (with usersCursor.fetch()?) and this could be the problem...

Thierry Templier
  • 198,364
  • 44
  • 396
  • 360
  • Thanks, but if I change to `this.users = Meteor.users.find().fetch();`, it becomes worse, I need manually refresh the page to see new status, even without orderByStatus pipe. – Hongbo Miao Feb 16 '16 at 02:38
  • What do the `fetch` / `find` methods return? Observables? Data? – Thierry Templier Feb 19 '16 at 09:12
  • find will return `Mongo.Cursor`, fetch will return `Array`. They both can use *ngFor directly – Hongbo Miao Feb 19 '16 at 16:05
  • Perhaps this question could help you: http://stackoverflow.com/questions/34456430/ngfor-doesnt-update-data-with-pipe-in-angular2/ – Thierry Templier Feb 19 '16 at 17:50
  • I did a test and changed my code in question a little bit. So now all because of the only one function users.sort(). Without it, the page can update automatically; with it, the page sometimes update automatically, sometimes not. – Hongbo Miao Feb 19 '16 at 19:43
  • Thanks, I read that. It is still not my case I feel. Mine is weird, the page sometimes update automatically, sometimes not after sorting. If not update automatically, I click that part of screen, it will update then. – Hongbo Miao Feb 19 '16 at 19:45
  • But the transform method is always called? Right? – Thierry Templier Feb 19 '16 at 19:52
  • No, when the page does not update automatically, the transform does not run (I use `console.log` in transform to test). Then after I clicking that part of page, the transform will run, and the page updates. – Hongbo Miao Feb 19 '16 at 19:54
  • sorry again, i tested again, even only `let users:Array = usersCursor.fetch();` and `return users;` without sort. It is still sometimes run, sometimes not. So the problem is related with these two, not because of sort. – Hongbo Miao Feb 19 '16 at 19:59
  • What is the change détection strategy of your component? Perhaps you could inject a ChangeDetectorRef and call its detectChanges method after doing the fetch... – Thierry Templier Feb 19 '16 at 20:06
  • `this.autorun()` will track when the Mongo cursor changes, I think I got some idea. Looks like my problem is also related with meteor change detection, not just because Angular2. I could add a sort when I do `Meteor.users.find();` (this way I got another bug so far `Cannot read property 'status' of undefined`) instead of using pipe to sort. I will post the answer here when I succeed. – Hongbo Miao Feb 19 '16 at 20:10