-
Notifications
You must be signed in to change notification settings - Fork 386
/
menu.effects.ts
115 lines (104 loc) · 3.77 KB
/
menu.effects.ts
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
import { ActivatedRoute } from '@angular/router';
import { MenuSection } from './menu.reducer';
import { hasNoValue, hasValue } from '../empty.util';
import { Actions, Effect, ofType } from '@ngrx/effects';
import { MenuService } from './menu.service';
import { Observable } from 'rxjs/internal/Observable';
import { Action } from '@ngrx/store';
import { ROUTER_NAVIGATED } from '@ngrx/router-store';
import { Injectable } from '@angular/core';
import { map, take, tap } from 'rxjs/operators';
import { MenuID } from './initial-menus-state';
/**
* Effects modifying the state of menus
*/
@Injectable()
export class MenuEffects {
/**
* On route change, build menu sections for every menu type depending on the current route data
*/
@Effect({dispatch: false})
public buildRouteMenuSections$: Observable<Action> = this.actions$
.pipe(
ofType(ROUTER_NAVIGATED),
tap(() => {
Object.values(MenuID).forEach((menuID) => {
this.buildRouteMenuSections(menuID);
});
})
);
constructor(private actions$: Actions,
private menuService: MenuService,
private route: ActivatedRoute) {
}
/**
* Build menu sections depending on the current route
* - Adds sections found in the current route data that aren't active yet
* - Removes sections that are active, but not present in the current route data
* @param menuID The menu to add/remove sections to/from
*/
buildRouteMenuSections(menuID: MenuID) {
this.menuService.getNonPersistentMenuSections(menuID).pipe(
map((sections) => sections.map((section) => section.id)),
take(1)
).subscribe((shouldNotPersistIDs: string[]) => {
const resolvedSections = this.resolveRouteMenuSections(this.route.root, menuID);
resolvedSections.forEach((section) => {
const index = shouldNotPersistIDs.indexOf(section.id);
if (index > -1) {
shouldNotPersistIDs.splice(index, 1);
} else {
this.menuService.addSection(menuID, section);
}
});
shouldNotPersistIDs.forEach((id) => {
this.menuService.removeSection(menuID, id);
});
});
}
/**
* Resolve menu sections defined in the current route data (including parent routes)
* @param route The route to resolve data for
* @param menuID The menu to resolve data for
*/
resolveRouteMenuSections(route: ActivatedRoute, menuID: MenuID): MenuSection[] {
const data = route.snapshot.data;
const params = route.snapshot.params;
const last: boolean = hasNoValue(route.firstChild);
if (hasValue(data) && hasValue(data.menu) && hasValue(data.menu[menuID])) {
let menuSections: MenuSection[] | MenuSection = data.menu[menuID];
menuSections = this.resolveSubstitutions(menuSections, params);
if (!last) {
return [...menuSections, ...this.resolveRouteMenuSections(route.firstChild, menuID)]
} else {
return [...menuSections];
}
}
return !last ? this.resolveRouteMenuSections(route.firstChild, menuID) : [];
}
private resolveSubstitutions(object, params) {
if (typeof object === 'string') {
let match: RegExpMatchArray;
do {
match = object.match(/:(\w+)/);
if (match) {
const substitute = params[match[1]];
if (hasValue(substitute)) {
object = object.replace(match[0], `${substitute}`);
}
}
} while (match);
} else if (Array.isArray(object)) {
object.forEach((entry, index) => {
object[index] = this.resolveSubstitutions(object[index], params);
});
} else {
Object.keys(object).forEach((key) => {
object = Object.assign({}, object, {
[key]: this.resolveSubstitutions(object[key], params)
});
});
}
return object;
}
}