Angular 角度2/4可见-为什么ng2 dragula在UI中一次拖放后发送多个拖放事件?
编辑有关问题标题更改的信息 最初的问题标题是: 角度2/4可观察-如何修改发射值的对象 在订阅中不触发更多事件 经过广泛的调查,这不是问题的原因,但这里的评论中有关于如何着手解决这一特定问题的建议。实际问题与多个ng2 dragula订户同时激活有关,因此我更新了问题标题以反映这一点Angular 角度2/4可见-为什么ng2 dragula在UI中一次拖放后发送多个拖放事件?,angular,rxjs,observable,ng2-dragula,Angular,Rxjs,Observable,Ng2 Dragula,编辑有关问题标题更改的信息 最初的问题标题是: 角度2/4可观察-如何修改发射值的对象 在订阅中不触发更多事件 经过广泛的调查,这不是问题的原因,但这里的评论中有关于如何着手解决这一特定问题的建议。实际问题与多个ng2 dragula订户同时激活有关,因此我更新了问题标题以反映这一点 我正在使用ng2 dragula插件并订阅dropModel事件 我面临的问题是,在订阅代码中,我需要通过重新安排模型中的其他项来修改模型。这会导致dropModel再次触发dropModel事件-它显然认为,因
我正在使用ng2 dragula插件并订阅dropModel事件 我面临的问题是,在订阅代码中,我需要通过重新安排模型中的其他项来修改模型。这会导致dropModel再次触发dropModel事件-它显然认为,因为我更改了列表中的模型位置,所以用户进行了拖放,而不是我的代码 我尝试了take(1),但这并没有解决问题-它只持续处理一个事件,所以当我在subscribe中更改模型时,显然它再次处理下一个(1) 代码如下:
this._dragulaService.dropModel.take(1).subscribe(() => {
// For ease, we just copy all the values into the model and then destroy
// the itemsControl, then patch all model values back to the form
// This is easier than working out which item was dragged and dropped where
// (and on each drop we want to save the model, so we would need to update it anyway)
this.itemsControl['controls'].forEach((formGroup, index) => {
this.template.template_items[index].sort = index; // ensures the API will always return items in the index order
console.log('copying ID', formGroup['controls'].id.value);
this.template.template_items[index].id = formGroup['controls'].id.value;
this.template.template_items[index].item_type = formGroup['controls'].item_type.value;
this.template.template_items[index].content = formGroup['controls'].content.value;
this.template.template_items[index].is_completed = formGroup['controls'].is_completed.value;
});
}
理想情况下,我希望“抓取”第一个丢弃事件(由用户发起),然后在订阅代码中取消订阅或停止接收更多事件,然后处理模型,最后重新订阅
我知道这有点奇怪——在订阅异步代码中,我需要以某种方式“暂停”订阅。虽然“暂停”并不完全正确,但实际上我希望在处理完当前事件之前,以某种方式防止触发新事件。暂停只会导致我处理自己的事件(如果有意义的话)。这可能吗
注意
dragula绑定到的模型是ItemsControl的动态数组,而不是正常意义上的纯数据模型。因此,我将数据从表单控件中提取出来并插入到实际的数据模型中
更新1
我决定记录dragula对绑定itemsControl(一个AbstractControls数组)的操作
在拖动之前,我记录数组中的实际内容:
itemsControl is now this: (4) [FormGroup, FormGroup, FormGroup, FormGroup]
在dropModel订阅处理程序中,我记录一个“Droped”事件和数组的长度。这是我拖放任何项目时的输出,始终是相同的输出:
dropped
length is 3
dropped
length is 3
dropped
length is 4
dropped
length is 5
dropped
length is 5
dropped
length is 4
dropped
length is 4
但是,如果我删除上面发布的代码(即,因此我不接触底层数据模型),这就是输出:
dropped
length is 4
dropped
length is 4
因此,至少这证明了,通过重新排序数据,我不仅引发了更多的事件(正如我所怀疑的),而且还产生了奇怪的副作用,即控件数组的长度在增加和减少(不确定为什么会这样)
考虑到这个输出,我需要一种只对发出的最后一个事件进行操作的方法
是否有办法仅从可观察事件中获取最后一个事件?
更新2
根据,这里真正的问题是ng2 dragula不支持将dropModel绑定到FormArray。但似乎有一个解决办法…仍在搜索 如果你总是得到两次发射,一个便宜的答案可能是使用一个标志来区分第一次和第二次发射
const haveModified = false;
this._dragulaService.dropModel.subscribe(() => {
if (!haveModified) {
this.itemsControl['controls'].forEach((formGroup, index) => {
...
});
haveModified = true;
} else {
haveModified = false;
}
});
}
更多Rx方法-检查下标值,如果两个发射相同(或属性相同),则使用distinctUntilChanged(比较:函数)
更新
我刚刚玩了一个,对类中的数据数组进行了简单的排序,我不会从dragula那里得到第二次发射
constructor(dragulaService: DragulaService) {
dragulaService.dropModel.subscribe(value => {
console.log(value)
console.log('target before sort', this.target)
this.target.sort();
console.log('target after sort', this.target)
})
}
我不能完全理解您正在执行的操作,但我看到您正在使用对HTML控件的引用。你能通过操纵基础数据来实现吗
更新#2
一直在使用比较器进行distinctUntilChanged(比较器)
,这涉及到比较项目的索引,这将使该解决方案可行
但是,由于源代码中存在一些漏洞,无法获取索引(dragula.provider.ts,第97行)
dropModel事件是
this.dropModel.emit([name, dropElm, target, source]);
但是dropElm既不在目标中也不在源中,所以我们不知道索引是什么。如果像这样发出dropIndex
会更好
this.dropModel.emit([name, dropElm, target, source, dropIndex]);
然后我们可以捕获重复的事件。因此,在所有这些之后,订阅ng2 dragula似乎有正确的方法和错误的方法: 走错了路,这就是我所拥有的:
dragulaService.dropModel.subscribe((result) => { ... }
正确的方法:
private destroy$ = new Subject();
constructor (private _dragulaService: DragulaService) {
this._dragulaService.dropModel.asObservable()
.takeUntil(this.destroy$).subscribe((result) => { ... }
}
ngOnDestroy() {
this.destroy$.next();
}
摘自
现在,我在每次拖放中只得到一个事件,对AbstractControls进行排序不会触发进一步的拖放事件
更新
感谢@RichardMatsen的评论,我进一步调查了上述代码修复问题的原因。它不是使用asObservable()来实现的,所以我不确定为什么我在上面提供的714问题的链接中建议这样做。可能需要asObservable(),以便我们可以正确地取消订阅(假设DragularService是EventEmitter)
之前我用的是我读到的:
DragularService.destroy(名称)
销毁名为name的drake实例
为了消灭“德雷克”:
ngOnDestroy(){
this._dragulaService.destroy('bag-container');
}
这并没有从Dragular服务中取消订阅。因此,当我导航回该组件时,它仍在发出事件,这就是为什么我得到了多个drop
另外,订阅和销毁并不是使用dragula服务的推荐方式,所以我已经提交了ng2 dragula的自述文件,以向未来的用户说明这一点。使用throttleTime(0)或debounceTime(0)限制可观测值不会解决问题,是吗?@estus我不知道,但是我会试试。@estus看来debounceTime(0)确实解决了这个问题……你是否能够创建一个答案来解释为什么它会起作用?@estus好的,我的错,在我重新加载应用程序并进行测试之后
ngOnDestroy(){
this._dragulaService.destroy('bag-container');
}