Реализация ActivityManagerService в angular-8.x не работает - PullRequest
0 голосов
/ 06 июня 2019

Я реализую ActivityManagerService, который предоставит следующие методы:

  • getAllActivity (): получить все активные действия
  • gotoIndex ({ind, path}): если пользователь хочет перейти к определенной деятельности
  • goto (to: any [] | any, data ?: any): перейти к определенному маршруту или компоненту с предоставлением некоторых дополнительных данных
  • back (): получить возврат к предыдущему действию
  • open: открыть конкретное представление с предоставлением дополнительных данных;

Примечание : Реализация должна иметь следующее:

  1. Нет повторного рендеринга компонента, который уже отрендерен
  2. У нескольких маршрутов есть авторизация, поэтому некоторые маршруты защищены
  3. необязательные данные могут быть переданы на разные маршруты.

Моя реализация выглядит следующим образом:

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
...