Javascript Jquery UI可排序列表在Meteor模板中无法很好地处理反应式更新

Javascript Jquery UI可排序列表在Meteor模板中无法很好地处理反应式更新,javascript,jquery-ui,meteor,meteor-blaze,Javascript,Jquery Ui,Meteor,Meteor Blaze,我正试图用jQueryUI以中描述的方式实现对象的可排序列表 但是,我没有对单独文档的列表进行排序,而是对嵌入到单个文档中的对象列表进行排序。也就是说,我有这样一份文件: {name:“此Rolodex的名称”, 卡片:[{姓名:“…”,等级:0,id:“某些唯一id”}, {名称:“…”,排名:1,id:“其他唯一id”},…] } 我只是想把卡片整理一下。我的模板如下——它传递了一个Rolodex作为上下文: Rolodex名称:{{Name} {{{#每个分类卡片} {{>cardTe

我正试图用jQueryUI以中描述的方式实现对象的可排序列表

但是,我没有对单独文档的列表进行排序,而是对嵌入到单个文档中的对象列表进行排序。也就是说,我有这样一份文件:

{name:“此Rolodex的名称”,
卡片:[{姓名:“…”,等级:0,id:“某些唯一id”},
{名称:“…”,排名:1,id:“其他唯一id”},…]
}
我只是想把卡片整理一下。我的模板如下——它传递了一个Rolodex作为上下文:


Rolodex名称:{{Name}
{{{#每个分类卡片}
{{>cardTemplate}
{{/每个}}
和helper JS文件:

Template.rolodex.helpers({
sortedCards:函数(){
返回此.cards.sort(函数(cardA,cardB){
返回cardA.rank-cardB.rank;
});
}
});
Template.rolodex.rendered=函数(){
此.$(“.cards list”)。可排序({
停止:功能(e、ui){
//获取拖动的HTML元素和一个紧靠前/后的元素
var el=ui.item.get(0)
var before=ui.item.prev().get(0)
var after=ui.item.next().get(0)
//根据项目前后的排名计算新排名
var newRank;
如果(!之前){
//First position=>将排名设置为紧随其后小于卡
newRank=Blaze.getData(after.rank-1);
}否则如果(!之后){
//Last position=>将等级设置为大于紧随其后的卡
newRank=Blaze.getData(之前).rank+1;
}否则{
//前后平均
newRank=(Blaze.getData(after.rank+
Blaze.getData(before.rank)/2;
}
//Meteor方法,用于更新一张卡的属性
//Rolodex基于Rolodex和卡的ID
Meteor.call('卡片/更新',
Blaze.getData(ui.item.parent().get(0))。\u id,//Rolodex id
Blaze.getData(el.id),//卡id
{rank:newRank});
}
});
};
我遇到的问题是,在将一张卡排序到其预期位置后,DOM会随着该卡在一个新的错误位置而更新。服务器存储了正确的排名,刷新页面会使卡片列在正确的位置(至少在尝试另一种排序之前)

我对正在发生的事情的最好猜测是Meteor的模板系统似乎不理解jQueryUI已经移动了DOM元素,并且正在以错误的顺序反应性地更新我的模板

例如,假设我的卡片是:A,B,C。我移动C,这样我们现在有了C,A,B。JQuery UI相应地更新DOM并触发一个事件,导致C的排名更改为小于A

然而,Meteor不知道DOM已经被jQueryUI改变了。然而,它确实看到了从秩到C的变化,并根据先前关于列表顺序的假设反应性地更新了列表的顺序。在这种情况下,我们以B,C,A结束


关于我做错了什么,有什么建议吗?

流星反应迫使你选择谁负责DOM更新

虽然可以让Blaze呈现DOM,然后使用第三方库(通常是在
.rendered()
方法中调用的jQuery插件)对其进行操作,但您现在的情况是Blaze不知道DOM发生了什么,因此后续的每一次响应更新都不可能是一致的

这就是为什么对于交互式和反应式界面元素,我们需要一类新的插件/组件/包Meteor-aware(或更好的反应式aware)。请参见移植到Meteor与Meteoric的示例

总而言之,我克服这个问题的方法是编写一些反应式代码,在DB更新时负责删除和重建插件。这样,您可以恢复Blaze知道的原始DOM,让他更新它,然后重新调用您的jQuery插件。这是一个远(非常远)的最佳解决方案,但节省了我的一天几次


对于
.sortable()
来说,最好的解决方案可能是使用
集合.find()中的选项
{reactive:false}
禁用反应性
这样,当您使用
Meteor.call更新卡的属性时,
不会重新绘制,但您的界面已经是一致的。

Meteor/Blaze使用
\u id
属性来识别数据对象并将它们链接到DOM元素。这不仅适用于集合游标返回的文档数组,而且适用于任何对象数组。所以在上面的问题中,问题是我使用了
id
值来识别每张卡,而不是
\u id
。将
id
切换到
\u id
可以解决此问题,并允许Blaze正确更新DOM,即使该DOM以前已被JQuery UI的可排序插件修改过。

感谢您的快速响应。我真的不想禁用反应性(也就是说,如果服务器说应该禁用,我确实希望采用这种方法),这样就可能只剩下销毁和重建。也就是说,我有点困惑,为什么它似乎可以处理集合中的文档集,而不是单个文档中的嵌入式数组。理论上,这两种情况都会触发DOM和Blaze模型之间相同的不匹配。好的,当jQuery组件完全破坏DOM以实现其目标时,我的解释适用。
.sortable()
并非如此,因此它可能与代码的逻辑有关。例如,它来自哪里?根据您的型号,它是
未定义的
。也许如果你发布一个完整的测试用例应用程序,我可以彻底检查它。啊,你的评论帮我弄明白了。我的模型确实有一个
id