diff --git a/npm/ng-packs/packages/core/src/lib/core.module.ts b/npm/ng-packs/packages/core/src/lib/core.module.ts index 9e822a4823..4b657fe8bb 100644 --- a/npm/ng-packs/packages/core/src/lib/core.module.ts +++ b/npm/ng-packs/packages/core/src/lib/core.module.ts @@ -20,6 +20,8 @@ import { SessionState } from './states/session.state'; import { getInitialData } from './utils/initial-utils'; import { EllipsisDirective } from './directives/ellipsis.directive'; import { AutofocusDirective } from './directives/autofocus.directive'; +import { InputEventDebounceDirective } from './directives/debounce.directive'; +import { ClickEventStopPropagationDirective } from './directives/stop-propagation.directive'; @NgModule({ imports: [ @@ -40,6 +42,8 @@ import { AutofocusDirective } from './directives/autofocus.directive'; LocalizationPipe, PermissionDirective, VisibilityDirective, + InputEventDebounceDirective, + ClickEventStopPropagationDirective, ], exports: [ CommonModule, @@ -54,7 +58,9 @@ import { AutofocusDirective } from './directives/autofocus.directive'; LocalizationPipe, PermissionDirective, VisibilityDirective, + InputEventDebounceDirective, LocalizationPipe, + ClickEventStopPropagationDirective, ], providers: [LocalizationPipe], entryComponents: [RouterOutletComponent, DynamicLayoutComponent], diff --git a/npm/ng-packs/packages/core/src/lib/directives/debounce.directive.ts b/npm/ng-packs/packages/core/src/lib/directives/debounce.directive.ts new file mode 100644 index 0000000000..144c43d4e2 --- /dev/null +++ b/npm/ng-packs/packages/core/src/lib/directives/debounce.directive.ts @@ -0,0 +1,26 @@ +import { Directive, Output, Renderer2, ElementRef, OnInit, EventEmitter, Input } from '@angular/core'; +import { fromEvent } from 'rxjs'; +import { debounceTime } from 'rxjs/operators'; +import { takeUntilDestroy } from '@ngx-validate/core'; + +@Directive({ + selector: '[input.debounce]', +}) +export class InputEventDebounceDirective implements OnInit { + @Input() debounce: number = 300; + + @Output('input.debounce') debounceEvent = new EventEmitter(); + + constructor(private renderer: Renderer2, private el: ElementRef) {} + + ngOnInit(): void { + fromEvent(this.el.nativeElement, 'input') + .pipe( + debounceTime(this.debounce), + takeUntilDestroy(this), + ) + .subscribe((event: Event) => { + this.debounceEvent.emit(event); + }); + } +} diff --git a/npm/ng-packs/packages/core/src/lib/directives/stop-propagation.directive.ts b/npm/ng-packs/packages/core/src/lib/directives/stop-propagation.directive.ts new file mode 100644 index 0000000000..ffa2e9e10b --- /dev/null +++ b/npm/ng-packs/packages/core/src/lib/directives/stop-propagation.directive.ts @@ -0,0 +1,21 @@ +import { Directive, ElementRef, EventEmitter, OnInit, Output, Renderer2 } from '@angular/core'; +import { fromEvent } from 'rxjs'; +import { takeUntilDestroy } from '@ngx-validate/core'; + +@Directive({ + selector: '[click.stop]', +}) +export class ClickEventStopPropagationDirective implements OnInit { + @Output('click.stop') stopPropEvent = new EventEmitter(); + + constructor(private renderer: Renderer2, private el: ElementRef) {} + + ngOnInit(): void { + fromEvent(this.el.nativeElement, 'click') + .pipe(takeUntilDestroy(this)) + .subscribe((event: MouseEvent) => { + event.stopPropagation(); + this.stopPropEvent.emit(event); + }); + } +} diff --git a/npm/ng-packs/packages/identity/src/lib/components/roles/roles.component.html b/npm/ng-packs/packages/identity/src/lib/components/roles/roles.component.html index af162133da..546a768006 100644 --- a/npm/ng-packs/packages/identity/src/lib/components/roles/roles.component.html +++ b/npm/ng-packs/packages/identity/src/lib/components/roles/roles.component.html @@ -18,7 +18,7 @@ type="search" class="form-control form-control-sm" [placeholder]="'AbpUi::PagerSearch' | abpLocalization" - (input)="search$.next($event.target.value)" + (input.debounce)="onSearch($event.target.value)" /> ; @@ -42,18 +42,14 @@ export class RolesComponent implements OnInit { loading: boolean = false; - search$ = new Subject(); - @ViewChild('modalContent', { static: false }) modalContent: TemplateRef; constructor(private confirmationService: ConfirmationService, private fb: FormBuilder, private store: Store) {} - ngOnInit() { - this.search$.pipe(debounceTime(300)).subscribe(value => { - this.pageQuery.filter = value; - this.get(); - }); + onSearch(value) { + this.pageQuery.filter = value; + this.get(); } createForm() { diff --git a/npm/ng-packs/packages/identity/src/lib/components/users/users.component.html b/npm/ng-packs/packages/identity/src/lib/components/users/users.component.html index 9d5aa0a9f0..03f5dcb605 100644 --- a/npm/ng-packs/packages/identity/src/lib/components/users/users.component.html +++ b/npm/ng-packs/packages/identity/src/lib/components/users/users.component.html @@ -24,7 +24,7 @@ type="search" class="form-control form-control-sm" [placeholder]="'AbpUi::PagerSearch' | abpLocalization" - (input)="search$.next($event.target.value)" + (input.debounce)="onSearch($event.target.value)" /> ; @@ -50,8 +50,6 @@ export class UsersComponent implements OnInit { loading: boolean = false; - search$ = new Subject(); - trackByFn: TrackByFunction = (index, item) => Object.keys(item)[0] || index; get roleGroups(): FormGroup[] { @@ -60,11 +58,9 @@ export class UsersComponent implements OnInit { constructor(private confirmationService: ConfirmationService, private fb: FormBuilder, private store: Store) {} - ngOnInit() { - this.search$.pipe(debounceTime(300)).subscribe(value => { - this.pageQuery.filter = value; - this.get(); - }); + onSearch(value) { + this.pageQuery.filter = value; + this.get(); } buildForm() { diff --git a/npm/ng-packs/packages/tenant-management/src/lib/components/tenants/tenants.component.html b/npm/ng-packs/packages/tenant-management/src/lib/components/tenants/tenants.component.html index ec059131e0..b8c206a74d 100644 --- a/npm/ng-packs/packages/tenant-management/src/lib/components/tenants/tenants.component.html +++ b/npm/ng-packs/packages/tenant-management/src/lib/components/tenants/tenants.component.html @@ -27,7 +27,7 @@ type="search" class="form-control form-control-sm" [placeholder]="'AbpUi::PagerSearch' | abpLocalization" - (input)="search$.next($event.target.value)" + (input.debounce)="onSearch($event.target.value)" /> ; @@ -52,8 +52,6 @@ export class TenantsComponent implements OnInit { loading: boolean = false; - search$ = new Subject(); - get useSharedDatabase(): boolean { return this.defaultConnectionStringForm.get('useSharedDatabase').value; } @@ -75,11 +73,9 @@ export class TenantsComponent implements OnInit { private store: Store, ) {} - ngOnInit() { - this.search$.pipe(debounceTime(300)).subscribe(value => { - this.pageQuery.filter = value; - this.get(); - }); + onSearch(value) { + this.pageQuery.filter = value; + this.get(); } private createTenantForm() {