Skip to content

Commit

Permalink
feat(ngrx): move tu .subscribe() less architecture, use | async pipe …
Browse files Browse the repository at this point in the history
…instead
  • Loading branch information
tomastrajan committed Nov 7, 2018
1 parent 03cf07a commit 24e80e4
Show file tree
Hide file tree
Showing 38 changed files with 374 additions and 487 deletions.
6 changes: 3 additions & 3 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -15,10 +15,10 @@
"clean": "rimraf ./dist/",
"server": "node ./server.js",
"prod": "npm run clean && npm run build:prod && npm run server",
"ci": "npm run clean && npm run prettier:ci && ng lint && ng test --configuration=test --browsers ChromeTravisCi --code-coverage && ng e2e && npm run cy:ci && npm run accessibility && npm run build:prod -- --deploy-url /angular-ngrx-material-starter/ --base-href /angular-ngrx-material-starter",
"ci": "npm run clean && npm run format:test && ng lint && ng test --configuration=test --browsers ChromeTravisCi --code-coverage && ng e2e && npm run cy:ci && npm run accessibility && npm run build:prod -- --deploy-url /angular-ngrx-material-starter/ --base-href /angular-ngrx-material-starter",
"release": "standard-version && git push --follow-tags origin master",
"prettier": "prettier {src,e2e,cypress}/**/*.{ts,json,md,scss} --write",
"prettier:ci": "prettier {src,e2e,cypress}/**/*.{ts,json,md,scss} --list-different",
"format:write": "prettier {src,e2e,cypress}/**/*.{ts,json,md,scss} --write",
"format:test": "prettier {src,e2e,cypress}/**/*.{ts,json,md,scss} --list-different",
"analyze": "npm run clean && npm run build:prod -- --stats-json && webpack-bundle-analyzer ./dist/stats.json",
"contributors:add": "all-contributors add",
"contributors:generate": "all-contributors generate && node .all-contributors-html.js",
Expand Down
2 changes: 0 additions & 2 deletions src/app/app.component.ts
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,6 @@ import {
NIGHT_MODE_THEME,
selectSettings,
SettingsState,
ActionSettingsPersist,
ActionSettingsChangeLanguage,
ActionSettingsChangeAnimationsPageDisabled
} from './settings';
Expand Down Expand Up @@ -102,7 +101,6 @@ export class AppComponent implements OnInit, OnDestroy {

onLanguageSelect({ value: language }) {
this.store.dispatch(new ActionSettingsChangeLanguage({ language }));
this.store.dispatch(new ActionSettingsPersist({ settings: this.settings }));
}

private subscribeToIsAuthenticated() {
Expand Down
2 changes: 1 addition & 1 deletion src/app/core/animations/route.animations.ts
Original file line number Diff line number Diff line change
Expand Up @@ -50,7 +50,7 @@ const STEPS_ALL: any[] = [
query(
':enter .' + ROUTE_ANIMATIONS_ELEMENTS,
stagger(75, [
style({ transform: 'translateY(15%)', opacity: 0 }),
style({ transform: 'translateY(10%)', opacity: 0 }),
animate(
'0.5s ease-in-out',
style({ transform: 'translateY(0%)', opacity: 1 })
Expand Down
9 changes: 7 additions & 2 deletions src/app/core/auth/auth.effects.spec.ts
Original file line number Diff line number Diff line change
@@ -1,9 +1,14 @@
import { Router } from '@angular/router';
import { LocalStorageService } from '@app/core';
import { ActionAuthLogin, ActionAuthLogout } from '@app/core/auth/auth.actions';
import { Actions, getEffectsMetadata } from '@ngrx/effects';
import { cold } from 'jasmine-marbles';
import { EMPTY } from 'rxjs';

import {
LocalStorageService,
ActionAuthLogin,
ActionAuthLogout
} from '@app/core';

import { AuthEffects, AUTH_KEY } from './auth.effects';

describe('AuthEffects', () => {
Expand Down
10 changes: 5 additions & 5 deletions src/app/core/core.module.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,21 +6,21 @@ import { EffectsModule } from '@ngrx/effects';
import { StoreDevtoolsModule } from '@ngrx/store-devtools';
import { TranslateModule, TranslateLoader } from '@ngx-translate/core';
import { TranslateHttpLoader } from '@ngx-translate/http-loader';
import {
StoreRouterConnectingModule,
RouterStateSerializer
} from '@ngrx/router-store';

import { environment } from '@env/environment';

import { httpInterceptorProviders } from './http-interceptors';
import { LocalStorageService } from './local-storage/local-storage.service';
import { AuthEffects } from './auth/auth.effects';
import { AuthGuardService } from './auth/auth-guard.service';
import { AnimationsService } from './animations/animations.service';
import { TitleService } from './title/title.service';
import { reducers, metaReducers } from './core.state';
import { AppErrorHandler } from './error-handler/app-error-handler.service';
import { httpInterceptorProviders } from '@app/core/http-interceptors';
import {
StoreRouterConnectingModule,
RouterStateSerializer
} from '@ngrx/router-store';
import { CustomSerializer } from './router/custom-serializer';
import { NotificationService } from './notifications/notification.service';

Expand Down
1 change: 1 addition & 0 deletions src/app/core/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ export * from './auth/auth.reducer';
export * from './auth/auth.actions';
export * from './auth/auth.selectors';
export * from './auth/auth-guard.service';
export * from './notifications/notification.service';
export * from './router/router.state';
export * from './title/title.service';
export * from './core.state';
Expand Down
7 changes: 7 additions & 0 deletions src/app/examples/examples/examples.component.html
Original file line number Diff line number Diff line change
@@ -1,3 +1,10 @@
<ng-container *ngIf="language$ | async as language">
{{updateLanguage(language)}}
</ng-container>
<ng-container *ngIf="activatedRouteSnapshot$ | async as snapshot">
{{updateTitle(snapshot)}}
</ng-container>

<nav mat-tab-nav-bar class="d-none d-sm-flex">
<a mat-tab-link
*ngFor="let e of examples"
Expand Down
68 changes: 23 additions & 45 deletions src/app/examples/examples/examples.component.ts
Original file line number Diff line number Diff line change
@@ -1,24 +1,17 @@
import { Store, select } from '@ngrx/store';
import {
Component,
OnDestroy,
OnInit,
ChangeDetectionStrategy
} from '@angular/core';
import { Component, OnInit, ChangeDetectionStrategy } from '@angular/core';
import { TranslateService } from '@ngx-translate/core';
import { ActivationEnd, Router } from '@angular/router';
import { Observable, Subject } from 'rxjs';
import { filter, takeUntil, map } from 'rxjs/operators';
import { ActivatedRouteSnapshot, ActivationEnd, Router } from '@angular/router';
import { Observable } from 'rxjs';
import { filter, map } from 'rxjs/operators';

import { routeAnimations, TitleService } from '@app/core';
import { routeAnimations, TitleService, selectAuth } from '@app/core';
import {
State as BaseSettingsState,
selectSettings,
SettingsState
selectSettingsLanguage
} from '@app/settings';

import { State as BaseExamplesState } from '../examples.state';
import { selectAuth } from '@app/core/auth/auth.selectors';

interface State extends BaseSettingsState, BaseExamplesState {}

Expand All @@ -29,9 +22,10 @@ interface State extends BaseSettingsState, BaseExamplesState {}
animations: [routeAnimations],
changeDetection: ChangeDetectionStrategy.OnPush
})
export class ExamplesComponent implements OnInit, OnDestroy {
private unsubscribe$: Subject<void> = new Subject<void>();
export class ExamplesComponent implements OnInit {
isAuthenticated$: Observable<boolean>;
language$: Observable<string>;
activatedRouteSnapshot$: Observable<ActivatedRouteSnapshot>;

examples = [
{ link: 'todos', label: 'anms.examples.menu.todos' },
Expand All @@ -51,44 +45,28 @@ export class ExamplesComponent implements OnInit, OnDestroy {
) {}

ngOnInit(): void {
this.titleService.setTitle(
this.router.routerState.snapshot.root,
this.translate
);
this.translate.setDefaultLang('en');
this.subscribeToSettings();
this.subscribeToRouterEvents();

this.isAuthenticated$ = this.store.pipe(
select(selectAuth),
map(auth => auth.isAuthenticated)
);
this.language$ = this.store.pipe(select(selectSettingsLanguage));
this.activatedRouteSnapshot$ = this.router.events.pipe(
filter(event => event instanceof ActivationEnd),
map((event: ActivationEnd) => event.snapshot)
);
}

ngOnDestroy(): void {
this.unsubscribe$.next();
this.unsubscribe$.complete();
}

private subscribeToSettings() {
this.store
.pipe(
select(selectSettings),
takeUntil(this.unsubscribe$)
)
.subscribe((settings: SettingsState) =>
this.translate.use(settings.language)
);
updateLanguage(language: string) {
this.translate.use(language);
}

private subscribeToRouterEvents() {
this.titleService.setTitle(
this.router.routerState.snapshot.root,
this.translate
);
this.router.events
.pipe(
filter(event => event instanceof ActivationEnd),
map((event: ActivationEnd) => event.snapshot),
takeUntil(this.unsubscribe$)
)
.subscribe(snapshot =>
this.titleService.setTitle(snapshot, this.translate)
);
updateTitle(activatedRouteSnapshot: ActivatedRouteSnapshot) {
this.titleService.setTitle(activatedRouteSnapshot, this.translate);
}
}
6 changes: 4 additions & 2 deletions src/app/examples/form/components/form.component.html
Original file line number Diff line number Diff line change
Expand Up @@ -4,8 +4,10 @@
<h1 class="main-heading">{{ 'anms.examples.form.title' | translate }}</h1>
</div>
</div>

<form [formGroup]="form" (ngSubmit)="onSubmit()">
<ng-container *ngIf="formValueChanges$ | async as updatedForm">
{{update(updatedForm)}}
</ng-container>
<form [formGroup]="form" (ngSubmit)="submit()">
<div class="row justify-content-center">
<div class="col-md-8">
<mat-card>
Expand Down
3 changes: 2 additions & 1 deletion src/app/examples/form/components/form.component.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,8 @@ import {
} from '@angular-extensions/testing-library';

import { MockStore, TestingModule } from '@testing/utils';
import { NotificationService } from '@app/core/notifications/notification.service';
import { NotificationService } from '@app/core';

import { State } from '../../examples.state';
import { FormState } from '../form.model';
import { FormComponent } from './form.component';
Expand Down
54 changes: 20 additions & 34 deletions src/app/examples/form/components/form.component.ts
Original file line number Diff line number Diff line change
@@ -1,32 +1,24 @@
import {
Component,
OnInit,
OnDestroy,
ChangeDetectionStrategy
} from '@angular/core';
import { Component, OnInit, ChangeDetectionStrategy } from '@angular/core';
import { Validators, FormBuilder } from '@angular/forms';
import { Store, select } from '@ngrx/store';
import { Subject } from 'rxjs';
import { takeUntil, filter, debounceTime, take } from 'rxjs/operators';

import { ROUTE_ANIMATIONS_ELEMENTS } from '@app/core';
import { filter, debounceTime, take } from 'rxjs/operators';
import { TranslateService } from '@ngx-translate/core';
import { Observable } from 'rxjs';

import { ROUTE_ANIMATIONS_ELEMENTS, NotificationService } from '@app/core';

import { State } from '../../examples.state';
import { ActionFormUpdate, ActionFormReset } from '../form.actions';
import { selectForm } from '../form.selectors';
import { selectFormState } from '../form.selectors';
import { Form } from '../form.model';
import { NotificationService } from '@app/core/notifications/notification.service';

@Component({
selector: 'anms-form',
templateUrl: './form.component.html',
styleUrls: ['./form.component.scss'],
changeDetection: ChangeDetectionStrategy.OnPush
})
export class FormComponent implements OnInit, OnDestroy {
private unsubscribe$ = new Subject<void>();

export class FormComponent implements OnInit {
routeAnimationsElements = ROUTE_ANIMATIONS_ELEMENTS;

form = this.fb.group({
Expand All @@ -47,6 +39,8 @@ export class FormComponent implements OnInit, OnDestroy {
rating: [0, Validators.required]
});

formValueChanges$: Observable<Form>;

constructor(
private fb: FormBuilder,
private store: Store<State>,
Expand All @@ -55,31 +49,27 @@ export class FormComponent implements OnInit, OnDestroy {
) {}

ngOnInit() {
this.formValueChanges$ = this.form.valueChanges.pipe(
debounceTime(500),
filter((form: Form) => form.autosave)
);
this.store
.pipe(
select(selectForm),
select(selectFormState),
take(1)
)
.subscribe(form => this.form.patchValue(form.form));
}

this.form.valueChanges
.pipe(
debounceTime(500),
filter((form: Form) => form.autosave),
takeUntil(this.unsubscribe$)
)
.subscribe((form: Form) =>
this.store.dispatch(new ActionFormUpdate({ form }))
);
update(form: Form) {
this.store.dispatch(new ActionFormUpdate({ form }));
}

ngOnDestroy(): void {
this.unsubscribe$.next();
this.unsubscribe$.complete();
this.form = null;
save() {
this.store.dispatch(new ActionFormUpdate({ form: this.form.value }));
}

onSubmit() {
submit() {
if (this.form.valid) {
this.save();
this.notificationService.info(
Expand All @@ -92,10 +82,6 @@ export class FormComponent implements OnInit, OnDestroy {
}
}

save() {
this.store.dispatch(new ActionFormUpdate({ form: this.form.value }));
}

reset() {
this.form.reset();
this.form.clearValidators();
Expand Down
4 changes: 2 additions & 2 deletions src/app/examples/form/form.selectors.ts
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
import { createSelector } from '@ngrx/store';

import { ExamplesState, selectExamples } from '@app/examples/examples.state';
import { ExamplesState, selectExamples } from '../examples.state';

export const selectForm = createSelector(
export const selectFormState = createSelector(
selectExamples,
(state: ExamplesState) => state.form
);
Original file line number Diff line number Diff line change
@@ -1,8 +1,9 @@
import { async, ComponentFixture, TestBed } from '@angular/core/testing';

import { NotificationsComponent } from './notifications.component';
import { TestingModule } from '@testing/utils';
import { NotificationService } from '@app/core/notifications/notification.service';
import { NotificationService } from '@app/core';

import { NotificationsComponent } from './notifications.component';

describe('NotificationsComponent', () => {
let component: NotificationsComponent;
Expand Down
Original file line number Diff line number Diff line change
@@ -1,11 +1,12 @@
import { Component, OnInit } from '@angular/core';
import { ROUTE_ANIMATIONS_ELEMENTS } from '@app/core';
import { NotificationService } from '@app/core/notifications/notification.service';
import { ChangeDetectionStrategy, Component, OnInit } from '@angular/core';

import { ROUTE_ANIMATIONS_ELEMENTS, NotificationService } from '@app/core';

@Component({
selector: 'anms-notifications',
templateUrl: './notifications.component.html',
styleUrls: ['./notifications.component.scss']
styleUrls: ['./notifications.component.scss'],
changeDetection: ChangeDetectionStrategy.OnPush
})
export class NotificationsComponent implements OnInit {
routeAnimationsElements = ROUTE_ANIMATIONS_ELEMENTS;
Expand Down
Loading

0 comments on commit 24e80e4

Please sign in to comment.