【问题标题】:Hide an HTML element using *ngIf when a user clicks outside of the specific element (Angular)当用户在特定元素之外单击时使用 *ngIf 隐藏 HTML 元素 (Angular)
【发布时间】:2020-08-26 11:07:09
【问题描述】:

如何在<div> 或其他元素上添加eventlistener,以隐藏我通过*ngIf 显示的内容 - 当我点击离开该元素时使用 Angular?

说明:当您单击 <label>Filter</label> 时,我通过 *ngIf 显示自定义 CSS 下拉列表,我希望用户能够在自定义中单击任意次数下拉菜单,但是当他们在自定义下拉菜单之外单击时,我想再次通过 *ngIf 隐藏自定义下拉菜单。

用户点击标签时调用的方法是showHideSectionOptions(),它将showHide变量切换为truefalse

这是我的 HTML 代码:

showHide = false;

<div class="form-row">
  <div class="form-group" id="showAndHideSections">
    <label (click)="showHideSectionOptions()">
      <img src="../../../assets/icons/Filter.png" alt="" class="mr-3">Filter</label>
    <div *ngIf="showHide" class="section-options">
       // show or hide content
    </div>
  </div>
</div>

这是我的组件代码:

showHideSectionOptions() {
  this.showHide = !this.showHide;
}

我已尝试按以下方式添加事件侦听器,但我无法设置 showHide 变量的值,因为我收到以下错误:“HTMLElement”类型上不存在属性“showHide”。 ts(2339):

body.addEventListener('click', function() {
  alert('wrapper');
}, false);
except.addEventListener('click', function(ev) {
  alert('except');
  ev.stopPropagation();
}, false);

提前致谢!

【问题讨论】:

标签: javascript angular


【解决方案1】:

首先,这已经有答案了here

但是,如果您想要 Angular 解决方案,您可以使用自定义指令:

@Directive({
  selector: '[clickOutside]'
})
export class ClickOutsideDirective {
  @Output()
  readonly clickOutside = new EventEmitter<MouseEvent>();

  @Input()
  include?: HTMLElement;

  constructor(private el: ElementRef<HTMLElement>) {}

  @HostListener('window:click', [ '$event' ])
  onClick(event: MouseEvent): void {
    if (this.isEventOutside(event)) {
      this.clickOutside.emit(this.event);
    }
  }

  private isEventOutside(event: MouseEvent): boolean {
    const target = event.target as HTMLElement;

    return !this.el.nativeElement.contains(target) &&
        (!this.include || !this.include.contains(target))
  }
}

你可以这样使用:

<div class="form-group" id="showAndHideSections">
  <label (click)="showHideSectionOptions()" #label>
    <img src="../../../assets/icons/Filter.png" alt="" class="mr-3">
    Filter
  </label>
  <div *ngIf="showHide" class="section-options"
       [include]="label" (clickOutside)="showHide = false">
     // show or hide content
  </div>
</div>

ngZone 之外运行的将是一个性能更高的。因为订阅发生在指令之外,当订阅Output时它将在ngZone内。

@Directive({
  selector: '[clickOutside]'
})
export class ClickOutsideDirective {
  @Input()
  include?: HTMLElement;

  @Output()
  readonly clickOutside = this.nz.runOutsideAngular(
    () => fromEvent(window, 'click').pipe(
      filter((event: MouseEvent) => this.isEventOutside(event))
    )
  );

  constructor(private el: ElementRef<HTMLElement>, private nz: NgZone) {}

  private isEventOutside(event: MouseEvent): boolean {
    const target = event.target as HTMLElement;

    return !this.el.nativeElement.contains(target) &&
        (!this.include || !this.include.contains(target))
  }
}

working stack

【讨论】:

  • 非常感谢您的回答。对此,我真的非常感激!我确实在寻找这样做的 Angular 方法。我对您的解决方案有一个问题;这与我需要的相反。我已经尝试了 2 个小时来修复它,但我做得不对。很抱歉,我还没有达到你的水平 :( 我希望使用 *ngIf="showHide" 显示的元素是你可以点击的唯一元素。
  • @onmyway 所以你也不希望它在用户点击filter 时切换?我已经更新了我的堆栈以反映这一点。如果您同意,我也会更新答案:)
  • 是的,您可以放下切换开关。我喜欢你的堆栈!正是我需要的:)
猜你喜欢
  • 2019-10-01
  • 1970-01-01
  • 1970-01-01
  • 2016-06-14
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2014-01-11
  • 1970-01-01
相关资源
最近更新 更多