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

Posted

技术标签:

【中文标题】Angular2-meteor - 在订阅函数中使用排序的 find() 后未定义的变量【英文标题】:Angular2-meteor - Variable undefined after a find() with sort in a subscribe function 【发布时间】:2016-04-21 11:46:31 【问题描述】:

我是 Meteor 和 angular2-meteor 包的新手,我正在尝试按照此处找到的精心制作的“社交”应用教程学习如何使用它们:Socially turorial。

在尝试我在那里看到的关于发布/订阅功能的内容时,我发现了一个我不知道如何解决的问题。为了清楚起见,我用这种结构做了一个非常简单的项目:

/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”字段中放置一个更高的数字,使它们切换位置,则应用程序将停止正常工作,并且浏览器控制台会显示:

例外:TypeError: l_test0 在 Socially@3:15 的 [test._id 中未定义]

例如,如果我有:

id:1 - num:6

id:2 - num:5

id:3 - num:4

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

id:3 - num:7 id:1 - 编号:6 id:2 - num:5

这给了我上述错误。

这可能很愚蠢,但由于我是一个真正的流星新手,我似乎无法理解出了什么问题,如果你能帮我一把,我会很高兴。

提前谢谢你。

编辑: 在我的原始项目中,我使用表单直接从页面添加/删除条目。在这个测试项目中,我删除了所有不必要的东西以使其尽可能简单并使用 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

【问题讨论】:

出于测试目的,您能否在模板中尝试以下语法:test?._idtest?.num(问号)。也许这是 angular2 中的一个错误,这是一种解决方法 @PierreDuc 感谢您的建议。我试着按照你说的做,错误显然消失了,但现在最后更新的条目消失了,直到我再次重新加载页面(我上一个例子中的“id:3 - num:7”)。 嗯,你在哪里更新 num 值?在 js 中还是在 mongo 中?如果在js中,如何? @PierreDuc 我编辑了我的原始消息来回答你的问题。 【参考方案1】:

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

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

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 移动到封闭的 &lt;template&gt; 标记:

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

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

【讨论】:

【参考方案2】:

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

问题是当使用sort 并且列表发生变化时,您现在不能将tests:Mongo.Cursor&lt;Test&gt;*ngFor 一起使用。 *ngFor 在 angular2-meteor 中完全不支持 Mongo.Cursor。所以你需要使用纯 Angular 2 方式。

你需要先fetch(),然后使用Array&lt;Test&gt;,否则当列表或列表顺序发生变化时会出现这个错误:

无法读取未定义的属性“XXX”

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

<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);
    );

参考github上的issue

【讨论】:

现在我可以发表评论了,把它移到这里:你不能只使用 autobind 参数来自动运行在 Angular 更改检测区域中运行回调,如下所示:this.autorun(() =&gt; this.tests = Tests.find(, sort: num: -1).fetch(); , true);跨度> @Trygve 该行只是确保您执行的工作在 Angular 区域内运行以让 UI 自动更新。对我来说,如果我不添加该行,除非我单击该部分,否则我的 UI 将不会更新。 对,但除非我误解了你,否则我相信this.autorun 的第二个参数会做同样的事情。 Reference here(搜索“自动绑定”)。 @Trygve 我做了一个复制品。我刚刚测试过,它们是不同的。代码是here。现在它使用Mongo.Cursor。运行meteor,使用Robomongo或类似应用打开数据库,你会看到集合tests中有两个项目。手动删除一项,UI会自动更新,当你删除第二项时,你会看到这个问题所说的错误。现在改成Array,还是手动删除一项,不使用ngZone,列表不会自动更新。 @Trygve 我的理解是this.autorun 是为了确保从服务器订阅最新数据。它是流星Tracker.autorun 的包装器。而NgZone 来自 Angular 2,这确保了 UI 更新。

以上是关于Angular2-meteor - 在订阅函数中使用排序的 find() 后未定义的变量的主要内容,如果未能解决你的问题,请参考以下文章

alanning:role,在 angular2-meteor 中导入问题

流星更新后,angular2-meteor 样本停止工作

在 Swift 中使用以函数为参数的 C 函数

如何在c ++中使函数返回字符串[重复]

使用函数[复制]在C中使单词小写

InstantiationException:在 Kotlin 中使实体字段不可为空时,没有实体的默认构造函数