Angular 角度2/4可见-为什么ng2 dragula在UI中一次拖放后发送多个拖放事件?

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事件-它显然认为,因

编辑有关问题标题更改的信息

最初的问题标题是:

角度2/4可观察-如何修改发射值的对象 在订阅中不触发更多事件

经过广泛的调查,这不是问题的原因,但这里的评论中有关于如何着手解决这一特定问题的建议。实际问题与多个ng2 dragula订户同时激活有关,因此我更新了问题标题以反映这一点


我正在使用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');
  }