Angular2-meteor - 在订阅函数中使用排序的 find() 后变量未定义

Angular2-meteor - Variable undefined after a find() with sort in a subscribe function

我是 Meteor 和 angular2-meteor 包的新手,我正在尝试按照此处提供的制作精良的 "Socially" 应用程序教程学习如何使用它们:Socially turorial.

在试验我在那里看到的有关 Publish/Subscribe 函数的内容时,我发现了一个我不知道如何解决的问题。为了清楚起见,我用这种结构做了一个非常简单的项目:

/typings/test.d.ts

interface Test {    
    _id?: string;
    num: number;
}

/collections/tests.ts

export var Tests = new Mongo.Collection<Test>('tests');

/server/main.ts

import './tests';

/server/test.ts - 正在发布所有内容

import {Tests} from 'collections/tests'; 

Meteor.publish('tests', function() {
    return Tests.find();
});

/client/app.ts - 订阅排序结果

import {Component, View} from 'angular2/core';

import {bootstrap} from 'angular2-meteor';

import {MeteorComponent} from 'angular2-meteor';

import {Tests} from 'collections/tests';

@Component({
    selector: 'app'
})

@View({
    templateUrl: 'client/app.html'
})

class Socially extends MeteorComponent {
    tests: Mongo.Cursor<Test>;

    constructor(){
        super();      
        this.subscribe('tests', () => {
            this.tests = Tests.find({}, {sort: {num: -1}});
        }, true);
    }
}

bootstrap(Socially);

/client/app.html - 一个简单的 ngFor,显示结果

<div>
    <ul>
        <li *ngFor="#test of tests">
            <p>{{test._id}}</p>
            <p>{{test.num}}</p>
        </li>
    </ul>
</div>

如果我使用 Mongo 控制台在数据库中插入或删除条目,一切正常。如果我更新现有条目 而不 更改它们的顺序,情况也是一样。但是,如果我尝试更新其中一个已存在的条目,在其 "num" 字段中放置一个更高的数字,使它们切换位置,应用程序将停止正常工作,并且浏览器控制台显示:

EXCEPTION: TypeError: l_test0 is undefined in [{{test._id}} in Socially@3:15]

例如,如果我有:

然后我尝试用 "num" 更新条目 4 将 "num" 改为 7,新结果应该是:

这是给我说的错误。

这可能很愚蠢,但由于我是 meteor 的真正新手,我似乎不明白哪里出了问题,如果你能帮助我,我会很高兴。

提前致谢。

编辑: 在我最初的项目中,我使用一个表单直接从页面 add/remove 条目。在这个测试项目中,我删除了所有不必要的东西以使其尽可能简单并使用 mongo 控制台:

db.tests.insert({_id: 1, num: 6})

db.tests.insert({_id: 2, num: 5})

db.tests.insert({_id: 3, num: 4})

db.tests.update({_id: 3}, {$set: {num: 7}})

如果我这样做:

db.tests.find()

显示:

{ "_id" : 1, "num" : 6 }

{ "_id" : 2, "num" : 5 }

{ "_id" : 3, "num" : 7 }

我希望那里有更好的答案,但我遇到了同样的问题并且一直在尝试一些事情。

我发现如果我在自动运行中向光标添加一个观察者,那么一切都会按预期运行:

this.tests.observeChanges({changed: () => {
    this.tests = Tests.find({}, {sort: {num: -1}});
}})

根据我一直在阅读的所有内容,这似乎不是必需的,但它确实对我有用。

为了防止它试图显示光标中短暂结束 undefined 的文档,我添加了一个 ngIf:

<li *ngFor="#test of tests" *ngIf="test">

编辑

我一直遇到一些难以确定的问题。阅读 this issue on ngFor and ngIf 后,我猜这是因为我在同一个元素上有 ngFor 和 ngIf,这显然不受支持。相反,他们建议将 ngIf 向上移动到封闭的 <template> 标记:

<template *ngIf="tests">
    <li *ngFor="#test of tests">
</template>

然而,这揭示了洪波的回答可能解决的根本问题。

更新:检查here,自angular2-meteor@0.5.1 以来该错误已修复!您现在可以使用 Mongo.Cursor

问题是当使用 sort 和列表更改时,您现在不能将 tests:Mongo.Cursor<Test>*ngFor 一起使用。 *ngFor 不支持 Mongo.Cursor 在 angular2-meteor 中完美。所以你需要使用纯 Angular 2 方式。

首先需要fetch(),然后使用Array<Test>,否则列表或列表顺序改变时会报错:

Cannot read property 'XXX' of undefined

所以最终的工作代码是这样的:

<div *ngFor="#test of tests">

</div>

// here you cannot use tests:Mongo.Cursor<Test>
tests:Array<Test>;
constructor() {
    super();
}
ngOnInit()
{
    this.subscribe('tests', () => {
        // autorun makes sure it get latest data
        this.autorun(() => {
            // here you need fetch first
            this.tests = Tests.find({}, {sort: {num: -1}}).fetch();
        }, true);
    });
}

参考 issue github