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?._id
和 test?.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 移动到封闭的 <template>
标记:
<template *ngIf="tests">
<li *ngFor="#test of tests">
</template>
然而,这揭示了可能是根本问题,洪波的回答解决了这个问题。
【讨论】:
【参考方案2】:更新:检查here,从 angular2-meteor@0.5.1 开始,该错误已修复!您现在可以使用Mongo.Cursor
。
问题是当使用sort
并且列表发生变化时,您现在不能将tests:Mongo.Cursor<Test>
与*ngFor
一起使用。 *ngFor
在 angular2-meteor 中完全不支持 Mongo.Cursor
。所以你需要使用纯 Angular 2 方式。
你需要先fetch()
,然后使用Array<Test>
,否则当列表或列表顺序发生变化时会出现这个错误:
无法读取未定义的属性“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(() => 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() 后未定义的变量的主要内容,如果未能解决你的问题,请参考以下文章