Angular@HostListener延迟,如果不使用默认值,则单击直到给出输入

Angular@HostListener延迟,如果不使用默认值,则单击直到给出输入,angular,rxjs,angular-directive,Angular,Rxjs,Angular Directive,我正在努力完成这件事。 我想实现的是以下目标 我有一个带有属性输入的指令,该指令检查这些属性,但是如果没有输入,它将使用指令本身定义的一些默认值。 但是点击处理本身总是在输入值到达之前发生。所以它总是检查错误的输入和默认的输入。 我也尝试过使用一些RXJ,但有些东西坏了。 指令看起来像这样 如果我在@Oninit subscription上记录异常,它甚至不会记录任何东西。 我如何调整指令使其工作,因为我需要它工作 一些代码可以更好地理解 private onChangeSub$ = new

我正在努力完成这件事。 我想实现的是以下目标

我有一个带有属性输入的指令,该指令检查这些属性,但是如果没有输入,它将使用指令本身定义的一些默认值。 但是点击处理本身总是在输入值到达之前发生。所以它总是检查错误的输入和默认的输入。 我也尝试过使用一些RXJ,但有些东西坏了。 指令看起来像这样

如果我在@Oninit subscription上记录异常,它甚至不会记录任何东西。 我如何调整指令使其工作,因为我需要它工作

一些代码可以更好地理解

  private onChangeSub$ = new Subject<AutoSaveExceptions>();
  private readonly clicks$ = new Subject<HTMLElement>();
  private someStream$: Subscription;

  private subscription$: Subscription;

  ngOnChanges(changes: SimpleChanges) {
    if (changes && changes['exceptions'] && changes['exceptions'].firstChange === true) {
      this.onChangeSub$.next(changes['exceptions'].currentValue);
      console.log(changes['exceptions'].currentValue);
    }
  }

ngOnInit() {
    console.log('oninit');
    this.subscription$ = this.onChangeSub$.pipe(
      defaultIfEmpty(this.inlineDefaultExceptions)
      ).subscribe((exceptions) => {
      this.exceptionAttributes = exceptions;
    });
    this.someStream$ = this.clicks$.pipe(
      delay(300),
    ).subscribe((target) => this.handleClicks(target));
  }

@HostListener('document:click', ['$event.target'])
  onClick(target: HTMLElement) {
    this.clicks$.next(target);
  }
@编辑:

操作符defaultIfEmpty在其源可观测完成时发出。但是,onChangeSub$是一个只有在调用onChangeSub$.complete时才完成的主题,因此您永远不会收到默认值

您可能正在寻找类似的内容:

timeoutWith(delay, of(this.inlineDefaultExceptions))
操作符defaultIfEmpty在其源可观察对象完成时发出。但是,onChangeSub$是一个只有在调用onChangeSub$.complete时才完成的主题,因此您永远不会收到默认值

您可能正在寻找类似的内容:

timeoutWith(delay, of(this.inlineDefaultExceptions))

首先,通常必须避免使用@HostListener'document:click',['$event.target']。这可能成为主要性能问题的根源。原因是,如果您的指令/组件的每个实例都具有此属性,那么您注册的文档点击次数与您拥有的指令/组件实例的数量一样多,所有这些都将触发大量更改检测。当心那件事

如果您想收听全局点击,您应该做的是:

const documentClick$: Observable<MouseEvent> = fromEvent(document, 'click').pipe(publish(), refCount());
export const DOCUMENT_CLICK = new InjectionToken('DOCUMENT_CLICK', {providedIn: 'root', factory: () => documentClick$});
然后你可以用它做任何类型的rxjs魔术,它将确保你在整个应用程序中最多有一个文档点击监听器。运行的更改检测更少-性能更好

现在,您可以过滤您的click$流,直到有更改:

this.documentClick$.pipe(
  withLatestFrom(this.onChangeSub$) // should not emit anything further until this stream emits, if it does, just add a filter
  filter(([event, changes]) => ... ) // check that it's not default
).subscribe(() => ...) // handle there for example
编辑: 您的指令可以检查编辑状态并将elementRef与上面提到的documentClick$I一起注入,然后当启用编辑时,指令可以侦听全局单击并以检查它是否在元素之外的方式处理它,如果是,则触发将导致自动保存的事件。
这是

首先,通常必须避免使用@HostListener'document:click',['$event.target']。这可能成为主要性能问题的根源。原因是,如果您的指令/组件的每个实例都具有此属性,那么您注册的文档点击次数与您拥有的指令/组件实例的数量一样多,所有这些都将触发大量更改检测。当心那件事

如果您想收听全局点击,您应该做的是:

const documentClick$: Observable<MouseEvent> = fromEvent(document, 'click').pipe(publish(), refCount());
export const DOCUMENT_CLICK = new InjectionToken('DOCUMENT_CLICK', {providedIn: 'root', factory: () => documentClick$});
然后你可以用它做任何类型的rxjs魔术,它将确保你在整个应用程序中最多有一个文档点击监听器。运行的更改检测更少-性能更好

现在,您可以过滤您的click$流,直到有更改:

this.documentClick$.pipe(
  withLatestFrom(this.onChangeSub$) // should not emit anything further until this stream emits, if it does, just add a filter
  filter(([event, changes]) => ... ) // check that it's not default
).subscribe(() => ...) // handle there for example
编辑: 您的指令可以检查编辑状态并将elementRef与上面提到的documentClick$I一起注入,然后当启用编辑时,指令可以侦听全局单击并以检查它是否在元素之外的方式处理它,如果是,则触发将导致自动保存的事件。
这是

我已经发布了第二个与你提到的内容相关的问题。我面临的是,使用此指令的组件的每个实例都会触发它不应该触发的逻辑。明天我将尝试你的解决方案。我应该如何以及在哪里收听全局鼠标单击?我已经尝试过你的解决方案,如果不过滤它,它仍然会将内容乘以我在页面上运行此duirective的组件的数量。如果我使用一些过滤逻辑,那么我将作为“更改”子项的最后一个未定义。同时,publish不接受我的任何参数。是的,你是对的,我只是太习惯于使用publishReplay1,但这不是你想要的,所以publish是一种方法。我可以帮助你更好,如果你建立一个堆栈闪电战或什么的话,这样我就可以看到它实际上是如何工作的,并帮助你让它工作。当然,它也会为每个组件执行代码,但是你只有一个全局点击监听器,这很重要。请告诉我你到底想实现什么,也许我可以帮助你想出更简单的方法。我已经发布了与你提到的内容相关的第二个问题。我面临的是,使用此指令的组件的每个实例都会触发它不应该触发的逻辑。明天我将尝试你的解决方案。我应该如何以及在哪里收听全局鼠标单击?我已经尝试过你的解决方案,如果不过滤它,它仍然会将内容乘以我在页面上运行此duirective的组件的数量。如果我使用一些过滤逻辑,那么我将作为最后一个来自更改子项的未定义
是的,你是对的,我只是太习惯于使用publishReplay1,但这不是你想要的,所以发布是一种方式。我可以帮助你更好,如果你建立一个堆栈闪电战或什么的话,这样我就可以看到它实际上是如何工作的,并帮助你让它工作。当然,它也会为每个组件执行代码,但是你只会得到一个全局点击监听器,这很重要。请告诉我你到底想实现什么,也许我可以帮你想出更简单的方法