Я реализую ActivityManagerService
, который предоставит следующие методы:
- getAllActivity (): получить все активные действия
- gotoIndex ({ind, path}): если пользователь хочет перейти к определенной деятельности
- goto (to: any [] | any, data ?: any): перейти к определенному маршруту или компоненту с предоставлением некоторых дополнительных данных
- back (): получить возврат к предыдущему действию
- open: открыть конкретное представление с предоставлением дополнительных данных;
Примечание : Реализация должна иметь следующее:
- Нет повторного рендеринга компонента, который уже отрендерен
- У нескольких маршрутов есть авторизация, поэтому некоторые маршруты защищены
- необязательные данные могут быть переданы на разные маршруты.
Моя реализация выглядит следующим образом:
import { Injectable, Injector, ReflectiveInjector } from "@angular/core";
import { Subject } from "rxjs";
import { CanActivate, CanDeactivate, Route, Router } from "@angular/router";
import { _I18N_ } from "../util/i18n/CustomI18nService";
const ComponentRouteMap = {
AbcComponent: {
path: "myabc",
name: _I18N_.MY_ABC,
icon_i: ["bi_ecommerce-dollar"]
},
XyzComponent: {
path: "myXYZ",
name: _I18N_.MY_XYZ,
icon_i: ["bi_setting-gear"]
},
PqrComponent: {
path: "myPqr/stu",
name: _I18N_.MY_PQR,
icon_i: ["bi_setting-log"]
},
};
@Injectable()
export class ActivityManagerService {
public mStates: any[] = [];
public mStatesRoutes: any[] = [];
private onNvigate = new Subject();
private _router: any[];
constructor(private injector: Injector, private router: Router) {
this._router = router.config;
}
getAllActivity() {
const ComponentRouteName = this.mStates
.map(i => i.instance)
.map((i, ind) => ({ ...ComponentRouteMap[i.ComponentRouteName], ind }));
return ComponentRouteName.reduce(
(a, b) => {
if (a.uniqObj[b.path]) {
return a;
} else {
a.uniqObj[b.path] = true;
a.items.push(b);
return a;
}
},
{ items: [], uniqObj: {} }
).items;
}
gotoIndex({ind, path}){
if(this.mStates.length && ind){
this.mStates = this.mStates.slice(0, ind)
}
this.goto(path);
}
goto(to: any[] | any, data?: any) {
if (!to && !this._router) return;
let component;
if (Array.isArray(to)) {
component = to[0];
data = to[1];
} else {
component = to;
}
if (typeof component === "string") {
let paths = component.split("/");
let path = paths.shift();
const d = this.findComponent(
this._router,
path === "" ? paths.shift() : path,
paths,
data
);
this.onNvigate.next(
Object.assign(d, {
initiated: comp => {
console.log("Login page initiated");
this.mStates.push(comp);
this.mStatesRoutes.push(component);
}
})
);
} else {
console.log(data);
this.onNvigate.next({
component,
data,
initiated: comp => this.mStates.push(comp)
});
}
}
back() {
let close = this.mStates[this.mStates.length ? this.mStates.length - 1 : 0];
if (close) {
if (typeof close.instance.onBack === "function") {
close.instance.onBack(() => {
this.mStates.pop().destroy();
});
} else {
this.mStates.pop().destroy();
}
}
if (!close || (close && this.mStates.length === 0)) {
this.goto(["/home"]);
}
}
doDestroy(comp, has) {
has = has || this.mStates.indexOf(comp);
if (has > -1) {
this.mStates.splice(has, 1)[0].destroy();
}
}
findComponent(routes, path, paths, data) {
console.log(path);
return new Promise((resolve, reject) => {
if (!routes) return reject();
let route: Route = routes.find(i => {
return i.path.toLowerCase() === path.toLowerCase();
});
if (route && paths.length === 0) {
this.canActive(route.canActivate, { path })
.then(() => this.canActive(route.canActivateChild, { path }))
.then(() => this.doResolve(route.resolve, { path }))
.then(() => {
console.log(
"Resolved component",
this.isActivityAlreadyOpened(route.component)
);
if (!this.isActivityAlreadyOpened(route.component))
resolve({ component: route.component, data });
else throw "Already activated";
})
.catch(err => {
console.log(err, "Resolved component");
reject();
});
} else if (route && paths.length > 0) {
let path = paths.shift();
this.findComponent(route.children, path, paths, data)
.then(resolve)
.catch(reject);
} else reject();
});
}
canActive(canActive: any[], { path }): Promise<any> {
return new Promise((resolve, reject) => {
if (!canActive || canActive.length === 0) return resolve();
canActive = Object.assign([], canActive);
let check = this.injector.get(canActive.shift());
let _check = check.canActivate || check.canDeactivate;
let doResolve = () => {
if (canActive.length > 0) {
this.canActive(canActive, { path })
.then(resolve)
.catch(reject);
} else {
resolve();
}
};
if (typeof _check === "function") {
_check
.bind(check)({ routeConfig: { path } })
.then(d => {
if (d === false) return reject("Component not allowed");
doResolve();
})
.catch(reject);
} else {
reject("Invalid can active function");
}
});
}
doResolve(resolvers: any, { path }, i = 0): Promise<any> {
console.log(i);
return new Promise((resolve, reject) => {
if (!resolvers || typeof resolvers !== "object") return resolve();
let r = Object.keys(resolvers);
console.log(resolvers, "resolvers", resolvers[r[i]], r, i);
if (r.length <= i) return resolve();
console.log(i);
let check = this.injector.get(resolvers[r[i]]);
let _check = check.resolve;
if (typeof _check === "function") {
_check
.bind(check)({ routeConfig: { path } })
.then(() => {
if (r.length > i) return this.doResolve(resolvers, { path }, i + 1);
else return true;
})
.then(resolve)
.catch(reject);
} else {
reject("Invalid can active function");
}
});
}
open(VIEW, data?: any) {
this.goto([VIEW, data]);
}
isActivityAlreadyOpened(component): boolean {
return this.mStates.length
? this.mStates[this.mStates.length - 1].instance instanceof component
: false;
}
}
Мои компоненты такие:
Машинопись:
import { ActivityManagerService } from "../xxx/state.service";
@Component({
selector: "app-abc",
templateUrl: "./app.component.html",
styleUrls: ["./app.component.css"]
})
export class AbcComponent {
public ComponentRouteName = 'AbcComponent';
constructor(
public activity: ActivityManagerService,
) {}
method1(){this.activity.open("my_abc", { app });}
}
HTML:
<div (click)="activity.goto(['/myXYZ'])">
<i class="bi_web-browser-plus"></i>
<h5 i18n custom-i18n>{{ i18n.RBC }}</h5>
</div>
- после нажатия выше, я не перехожу на URL