Skip to content

Commit

Permalink
feat: implement SubscriptionService instead of takeUntilDestroy
Browse files Browse the repository at this point in the history
resolves #4818
  • Loading branch information
mehmet-erim committed Jul 22, 2020
1 parent 8c50cdb commit 5ea30d4
Show file tree
Hide file tree
Showing 15 changed files with 175 additions and 169 deletions.
Original file line number Diff line number Diff line change
@@ -1,21 +1,18 @@
import { ConfigState, takeUntilDestroy } from '@abp/ng.core';
import { Component, Input, OnDestroy, OnInit, TemplateRef } from '@angular/core';
import { ConfigState, SubscriptionService } from '@abp/ng.core';
import { Component, Input, OnInit, TemplateRef } from '@angular/core';
import { Select, Store } from '@ngxs/store';
import { Observable } from 'rxjs';
import { Account } from '../../models/account';
import { eAccountComponents } from '../../enums/components';
import { Account } from '../../models/account';

@Component({
selector: 'abp-auth-wrapper',
templateUrl: './auth-wrapper.component.html',
exportAs: 'abpAuthWrapper',
providers: [SubscriptionService],
})
export class AuthWrapperComponent
implements
Account.AuthWrapperComponentInputs,
Account.AuthWrapperComponentOutputs,
OnInit,
OnDestroy {
implements Account.AuthWrapperComponentInputs, Account.AuthWrapperComponentOutputs, OnInit {
@Input()
readonly mainContentRef: TemplateRef<any>;

Expand All @@ -29,18 +26,16 @@ export class AuthWrapperComponent

tenantBoxKey = eAccountComponents.TenantBox;

constructor(private store: Store) {}
constructor(private store: Store, private subscription: SubscriptionService) {}

ngOnInit() {
this.store
.select(ConfigState.getSetting('Abp.Account.EnableLocalLogin'))
.pipe(takeUntilDestroy(this))
.subscribe(value => {
this.subscription.addOne(
this.store.select(ConfigState.getSetting('Abp.Account.EnableLocalLogin')),
value => {
if (value) {
this.enableLocalLogin = value.toLowerCase() !== 'false';
}
});
},
);
}

ngOnDestroy() {}
}
Original file line number Diff line number Diff line change
@@ -1,14 +1,14 @@
import { Component, Injector, OnDestroy, Optional, SkipSelf, Type } from '@angular/core';
import { Component, Injector, Optional, SkipSelf, Type } from '@angular/core';
import { ActivatedRoute, NavigationEnd, Router } from '@angular/router';
import { Store } from '@ngxs/store';
import { eLayoutType } from '../enums/common';
import { ABP } from '../models';
import { ReplaceableComponents } from '../models/replaceable-components';
import { LocalizationService } from '../services/localization.service';
import { RoutesService } from '../services/routes.service';
import { SubscriptionService } from '../services/subscription.service';
import { ReplaceableComponentsState } from '../states/replaceable-components.state';
import { findRoute, getRoutePath } from '../utils/route-utils';
import { takeUntilDestroy } from '../utils/rxjs-utils';
import { TreeNode } from '../utils/tree-utils';

@Component({
Expand All @@ -20,8 +20,9 @@ import { TreeNode } from '../utils/tree-utils';
><ng-container *ngIf="isLayoutVisible" [ngComponentOutlet]="layout"></ng-container
></ng-template>
`,
providers: [SubscriptionService],
})
export class DynamicLayoutComponent implements OnDestroy {
export class DynamicLayoutComponent {
layout: Type<any>;

// TODO: Consider a shared enum (eThemeSharedComponents) for known layouts
Expand All @@ -37,14 +38,15 @@ export class DynamicLayoutComponent implements OnDestroy {
injector: Injector,
private localizationService: LocalizationService,
private store: Store,
private subscription: SubscriptionService,
@Optional() @SkipSelf() dynamicLayoutComponent: DynamicLayoutComponent,
) {
if (dynamicLayoutComponent) return;
const route = injector.get(ActivatedRoute);
const router = injector.get(Router);
const routes = injector.get(RoutesService);

router.events.pipe(takeUntilDestroy(this)).subscribe(event => {
this.subscription.addOne(router.events, event => {
if (event instanceof NavigationEnd) {
let expectedLayout = (route.snapshot.data || {}).layout;

Expand Down Expand Up @@ -73,7 +75,7 @@ export class DynamicLayoutComponent implements OnDestroy {
}

private listenToLanguageChange() {
this.localizationService.languageChange.pipe(takeUntilDestroy(this)).subscribe(() => {
this.subscription.addOne(this.localizationService.languageChange, () => {
this.isLayoutVisible = false;
setTimeout(() => (this.isLayoutVisible = true), 0);
});
Expand All @@ -82,6 +84,4 @@ export class DynamicLayoutComponent implements OnDestroy {
private getComponent(key: string): ReplaceableComponents.ReplaceableComponent {
return this.store.selectSnapshot(ReplaceableComponentsState.getComponent(key));
}

ngOnDestroy() {}
}
Original file line number Diff line number Diff line change
@@ -1,39 +1,45 @@
import { Component, OnDestroy, OnInit, Type } from '@angular/core';
import { Component, OnInit, Type } from '@angular/core';
import { ActivatedRoute } from '@angular/router';
import { Store } from '@ngxs/store';
import { distinctUntilChanged } from 'rxjs/operators';
import { ABP } from '../models/common';
import { ReplaceableComponents } from '../models/replaceable-components';
import { SubscriptionService } from '../services/subscription.service';
import { ReplaceableComponentsState } from '../states/replaceable-components.state';
import { takeUntilDestroy } from '../utils/rxjs-utils';

@Component({
selector: 'abp-replaceable-route-container',
template: `
<ng-container *ngComponentOutlet="externalComponent || defaultComponent"></ng-container>
`,
providers: [SubscriptionService],
})
export class ReplaceableRouteContainerComponent implements OnInit, OnDestroy {
export class ReplaceableRouteContainerComponent implements OnInit {
defaultComponent: Type<any>;

componentKey: string;

externalComponent: Type<any>;

constructor(private route: ActivatedRoute, private store: Store) {}
constructor(
private route: ActivatedRoute,
private store: Store,
private subscription: SubscriptionService,
) {}

ngOnInit() {
this.defaultComponent = this.route.snapshot.data.replaceableComponent.defaultComponent;
this.componentKey = (this.route.snapshot.data
.replaceableComponent as ReplaceableComponents.RouteData).key;

this.store
const component$ = this.store
.select(ReplaceableComponentsState.getComponent(this.componentKey))
.pipe(takeUntilDestroy(this), distinctUntilChanged())
.subscribe((res = {} as ReplaceableComponents.ReplaceableComponent) => {
.pipe(distinctUntilChanged());

this.subscription.addOne(
component$,
(res = {} as ReplaceableComponents.ReplaceableComponent) => {
this.externalComponent = res.component;
});
},
);
}

ngOnDestroy() {}
}
29 changes: 10 additions & 19 deletions npm/ng-packs/packages/core/src/lib/directives/debounce.directive.ts
Original file line number Diff line number Diff line change
@@ -1,34 +1,25 @@
import {
Directive,
ElementRef,
EventEmitter,
Input,
OnDestroy,
OnInit,
Output,
} from '@angular/core';
import { takeUntilDestroy } from '../utils/rxjs-utils';
import { Directive, ElementRef, EventEmitter, Input, OnInit, Output } from '@angular/core';
import { fromEvent } from 'rxjs';
import { debounceTime } from 'rxjs/operators';
import { SubscriptionService } from '../services/subscription.service';

@Directive({
// tslint:disable-next-line: directive-selector
selector: '[input.debounce]',
providers: [SubscriptionService],
})
export class InputEventDebounceDirective implements OnInit, OnDestroy {
export class InputEventDebounceDirective implements OnInit {
@Input() debounce = 300;

@Output('input.debounce') readonly debounceEvent = new EventEmitter<Event>();

constructor(private el: ElementRef) {}
constructor(private el: ElementRef, private subscription: SubscriptionService) {}

ngOnInit(): void {
fromEvent(this.el.nativeElement, 'input')
.pipe(debounceTime(this.debounce), takeUntilDestroy(this))
.subscribe((event: Event) => {
this.debounceEvent.emit(event);
});
}
const input$ = fromEvent(this.el.nativeElement, 'input').pipe(debounceTime(this.debounce));

ngOnDestroy(): void {}
this.subscription.addOne(input$, (event: Event) => {
this.debounceEvent.emit(event);
});
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -4,23 +4,23 @@ import {
ElementRef,
EventEmitter,
Input,
OnDestroy,
OnInit,
Output,
Self,
} from '@angular/core';
import { FormControl, FormGroup, FormGroupDirective } from '@angular/forms';
import { fromEvent } from 'rxjs';
import { debounceTime, filter } from 'rxjs/operators';
import { takeUntilDestroy } from '../utils';
import { SubscriptionService } from '../services/subscription.service';

type Controls = { [key: string]: FormControl } | FormGroup[];

@Directive({
// tslint:disable-next-line: directive-selector
selector: 'form[ngSubmit][formGroup]',
providers: [SubscriptionService],
})
export class FormSubmitDirective implements OnInit, OnDestroy {
export class FormSubmitDirective implements OnInit {
@Input()
debounce = 200;

Expand All @@ -35,30 +35,30 @@ export class FormSubmitDirective implements OnInit, OnDestroy {
@Self() private formGroupDirective: FormGroupDirective,
private host: ElementRef<HTMLFormElement>,
private cdRef: ChangeDetectorRef,
private subscription: SubscriptionService,
) {}

ngOnInit() {
this.formGroupDirective.ngSubmit.pipe(takeUntilDestroy(this)).subscribe(() => {
this.subscription.addOne(this.formGroupDirective.ngSubmit, () => {
this.markAsDirty();
this.executedNgSubmit = true;
});

fromEvent(this.host.nativeElement as HTMLElement, 'keyup')
.pipe(
debounceTime(this.debounce),
filter((key: KeyboardEvent) => key && key.key === 'Enter'),
takeUntilDestroy(this),
)
.subscribe(() => {
if (!this.executedNgSubmit) {
this.host.nativeElement.dispatchEvent(new Event('submit', { bubbles: true, cancelable: true }));
}
const keyup$ = fromEvent(this.host.nativeElement as HTMLElement, 'keyup').pipe(
debounceTime(this.debounce),
filter((key: KeyboardEvent) => key && key.key === 'Enter'),
);

this.executedNgSubmit = false;
});
}
this.subscription.addOne(keyup$, () => {
if (!this.executedNgSubmit) {
this.host.nativeElement.dispatchEvent(
new Event('submit', { bubbles: true, cancelable: true }),
);
}

ngOnDestroy(): void {}
this.executedNgSubmit = false;
});
}

markAsDirty() {
const { form } = this.formGroupDirective;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,19 +2,18 @@ import {
Directive,
ElementRef,
Input,
OnChanges,
OnDestroy,
OnInit,
Renderer2,
ViewContainerRef,
TemplateRef,
Optional,
Renderer2,
SimpleChanges,
OnChanges,
TemplateRef,
ViewContainerRef,
} from '@angular/core';
import { Store } from '@ngxs/store';
import { ConfigState } from '../states';
import { takeUntilDestroy } from '../utils';
import { Subscription } from 'rxjs';
import { ConfigState } from '../states';

@Directive({
selector: '[abpPermission]',
Expand All @@ -39,15 +38,17 @@ export class PermissionDirective implements OnInit, OnDestroy, OnChanges {

this.subscription = this.store
.select(ConfigState.getGrantedPolicy(this.condition))
.pipe(takeUntilDestroy(this))
.subscribe(isGranted => {
if (this.templateRef && isGranted) {
this.vcRef.clear();
this.vcRef.createEmbeddedView(this.templateRef);
} else if (this.templateRef && !isGranted) {
this.vcRef.clear();
} else if (!isGranted && !this.templateRef) {
this.renderer.removeChild((this.elRef.nativeElement as HTMLElement).parentElement, this.elRef.nativeElement);
this.renderer.removeChild(
(this.elRef.nativeElement as HTMLElement).parentElement,
this.elRef.nativeElement,
);
}
});
}
Expand All @@ -58,7 +59,9 @@ export class PermissionDirective implements OnInit, OnDestroy, OnChanges {
}
}

ngOnDestroy(): void {}
ngOnDestroy(): void {
this.subscription.unsubscribe();
}

ngOnChanges({ condition }: SimpleChanges) {
if ((condition || { currentValue: null }).currentValue) {
Expand Down
Loading

0 comments on commit 5ea30d4

Please sign in to comment.