Использование ребенка как родителя для ребенка - Маршрутизатор, хлебные крошки, навигация - PullRequest
2 голосов
/ 26 апреля 2019

Итак, у меня есть приложение, которое состоит из панировочных сухарей , Параметры навигации и Функции , т. Е.

  • Экран настройки с основными опциями, эти опционные карты могут быть переменными, то есть не фиксированными до 3 enter image description here

  • Экран первого уровня, на котором пользователь выбрал опцию 1, посмотрите, как меняется хлебная крошка, эти карты опций могут быть переменными, т.е. не фиксированными в 3 enter image description here

    • Экран второго уровня, на котором пользователь выбрал опцию A, посмотрите, как и здесь меняется хлебная крошка, эти опционные карточки могут быть переменными, то есть не фиксированными в 3

enter image description here

На рисунках выше хорошо видны «хлебные крошки» и «Опции», но всякий раз, когда не остается никакой дополнительной опции или подопции, компонент компонента загружается или заменяет область контейнера опции.

Структура каталога моего приложения, как показано ниже,

enter image description here

Папка действий и навигации, представленная ниже, состоит из следующих файлов,

enter image description here

Ниже приведен код, который я написал,

core.module.ts

import { NgModule } from '@angular/core';
import { FooterComponent } from './footer/footer.component';
import { HeaderComponent } from './header/header.component';
import { NavigationComponent } from './navigation/navigation.component';
import { CommonModule } from '@angular/common';
import { FormsModule, ReactiveFormsModule } from '@angular/forms';
import { BrowserAnimationsModule } from '@angular/platform-browser/animations';
import { PMRoutingModule } from '../router/pmrouter.module';
import { MatPaginatorModule,
  MatSortModule,
  MatTableModule,
  MatFormFieldModule,
  MatInputModule,
  MatCheckboxModule,
  MatButtonModule,
  MatProgressSpinnerModule,
  MatOptionModule,
  MatSelectModule,
  MatDialogModule,
  MatAutocompleteModule,
  MatRadioModule,
  MatSnackBarModule,
  MatDatepickerModule,
  MatNativeDateModule} from '@angular/material';
import { ActionsListComponent } from './actions/actions-list.component';
import { ActionThumbnailComponent } from './actions/action-thumbnail.component';

@NgModule({
  imports: [
    CommonModule,
    FormsModule,
    BrowserAnimationsModule,
    MatPaginatorModule,
    MatSortModule,
    MatTableModule,
    MatFormFieldModule,
    MatInputModule,
    MatCheckboxModule,
    MatButtonModule,
    MatProgressSpinnerModule,
    MatOptionModule,
    MatSelectModule,
    ReactiveFormsModule,
    MatDialogModule,
    MatAutocompleteModule,
    MatRadioModule,
    MatSnackBarModule,
    MatDatepickerModule,
    MatDatepickerModule,
    MatNativeDateModule,
    PMRoutingModule
  ],
  declarations: [
    HeaderComponent,
    FooterComponent,
    NavigationComponent,
    ActionsListComponent,
    ActionThumbnailComponent
  ],
  exports: [
    HeaderComponent,
    FooterComponent,
    NavigationComponent,
    CommonModule,
    FormsModule,
    BrowserAnimationsModule,
    MatPaginatorModule,
    MatSortModule,
    MatTableModule,
    MatFormFieldModule,
    MatInputModule,
    MatCheckboxModule,
    MatButtonModule,
    MatProgressSpinnerModule,
    MatOptionModule,
    MatSelectModule,
    ReactiveFormsModule,
    MatDialogModule,
    MatAutocompleteModule,
    MatRadioModule,
    MatSnackBarModule,
    MatDatepickerModule,
    MatDatepickerModule,
    MatNativeDateModule,
    PMRoutingModule
  ]
})
export class CoreModule { }

navigation.component.ts

import { Component, OnInit } from '@angular/core';
import { Params, ActivatedRoute, Router, NavigationEnd, PRIMARY_OUTLET } from '@angular/router';
import { filter } from 'rxjs/operators';

interface IBreadcrumb {
  label: string;
  params: Params;
  url: string;
}

@Component({
  selector: 'app-navigation',
  templateUrl: './navigation.component.html',
  styleUrls: ['./navigation.component.css']
})
export class NavigationComponent implements OnInit {

  public breadcrumbs: IBreadcrumb[];

  /**
   * @class DetailComponent
   * @constructor
   */
  constructor(
    private activatedRoute: ActivatedRoute,
    private router: Router
  ) {
    this.breadcrumbs = [];
  }

  /**
   * Let's go!
   *
   * @class DetailComponent
   * @method ngOnInit
   */
  ngOnInit() {
    const ROUTE_DATA_BREADCRUMB: string = "breadcrumb";

    //subscribe to the NavigationEnd event
    this.router.events.pipe(
      filter(event => event instanceof NavigationEnd))
      .subscribe(event => {
      //set breadcrumbs
      let root: ActivatedRoute = this.activatedRoute.root;
      this.breadcrumbs = this.getBreadcrumbs(root);
    });
  }

  /**
   * Returns array of IBreadcrumb objects that represent the breadcrumb
   *
   * @class DetailComponent
   * @method getBreadcrumbs
   * @param {ActivateRoute} route
   * @param {string} url
   * @param {IBreadcrumb[]} breadcrumbs
   */
  private getBreadcrumbs(route: ActivatedRoute, url: string='', breadcrumbs: IBreadcrumb[]=[]): IBreadcrumb[] {
    const ROUTE_DATA_BREADCRUMB: string = "breadcrumb";

    //get the child routes
    let children: ActivatedRoute[] = route.children;

    //return if there are no more children
    if (children.length === 0) {
      return breadcrumbs;
    }

    //iterate over each children
    for (let child of children) {

      console.log(child.url);

      //verify primary route
      if (child.outlet !== PRIMARY_OUTLET) {
        continue;
      }

      //verify the custom data property "breadcrumb" is specified on the route
      if (!child.snapshot.data.hasOwnProperty(ROUTE_DATA_BREADCRUMB)) {
        return this.getBreadcrumbs(child, url, breadcrumbs);
      }

      //get the route's URL segment
      let routeURL: string = child.snapshot.url.map(segment => segment.path).join("/");

      //append route URL to URL
      url += `/${routeURL}`;

      //add breadcrumb
      let breadcrumb: IBreadcrumb = {
        label: child.snapshot.data[ROUTE_DATA_BREADCRUMB],
        params: child.snapshot.params,
        url: url
      };
      breadcrumbs.push(breadcrumb);

      //recursive
      return this.getBreadcrumbs(child, url, breadcrumbs);
    }
  }


}

navigation.component.html

<nav class="spacing">
  <ol class="cd-breadcrumb triangle custom-icons">
    <li *ngFor="let breadcrumb of breadcrumbs; let i = index" [ngClass]="breadcrumbs.length === (i + 1) ? 'current' : ''">
      <div *ngIf="breadcrumbs.length === (i + 1);then last else parent"></div>
      <ng-template #last>
          <em>{{ breadcrumb.label }}</em>
      </ng-template>
      <ng-template #parent>
          <a [routerLink]="breadcrumb.url">{{ breadcrumb.label }}</a>
      </ng-template>
    </li>
  </ol>
</nav>

действия-list.component.ts

import { Component, OnInit } from '@angular/core';
import { Route, Router, NavigationEnd, ActivatedRoute, UrlSegment } from '@angular/router';
import { filter } from 'rxjs/operators';

@Component({

  templateUrl: './actions-list.component.html',
  styleUrls: ['./actions-list.component.css']
})
export class ActionsListComponent implements OnInit {

  rowActionClass: string[] = ['col-md-3 col-lg-2 col-sm-4 col-xs-6 card-short', 'col-md-3 col-lg-3 col-sm-4 col-xs-6 card-long'];

  allRoutes = [] as Imenuoption[];
  actions = [] as Imenuoption[];
  errorMessage: string;
  event = {} as NavigationEnd;

  constructor(private router: Router) {

    this.router.events.pipe(
      filter(event => event instanceof NavigationEnd))
      .subscribe(event => {
        this.allRoutes = [];
        this.getAllRoutes('', this.router.config);
        this.setupActions();
    });
  }

  ngOnInit(): void {
  }

  setupActions() {

    this.actions = [];
    const currentRoute: string[] = this.router.url.split('/');

    for (let i = 0; i < this.allRoutes.length; i++) {
      const str = this.allRoutes[i];
      const rData: string[] = str.navURL.split('/');
        if (this.router.url !== '/' && currentRoute.length === rData.length - 1 ) {
          this.actions.push(this.allRoutes[i]);
        }
    }
  }

  getAllRoutes(parent: String, config: Route[]): Imenuoption[] {
    for (let i = 0; i < config.length; i++) {
      const route = config[i];

      const option = {} as Imenuoption;
      option.navURL = parent + '/' + route.path;
      option.imageURL = option.navURL === '/' ? '' : route.data.imageURL;
      option.description = option.navURL === '/' ? '' : route.data.breadcrumb;

      this.allRoutes.push(option);

      if (route.children) {
        const currentPath = route.path ? parent + '/' + route.path : parent;
        this.getAllRoutes(currentPath, route.children);
      }
    }
    return this.allRoutes;
  }

}

действия-list.component.html

<div class="row">
  <div class="col-md-10 col-lg-10 col-md-offset-1 col-lg-offset-1">
    <div class="row">
      <ng-template ngFor let-actionCard="$implicit" [ngForOf]="actions">
        <div [ngClass]="actions.length > 4 ? rowActionClass[0] : rowActionClass[1]">
          <div *ngIf="actions.length > 4 ;then small else large"></div>
          <ng-template #small>
            <app-action-thumbnail [action]="actionCard" [cssCardHeight]="0"></app-action-thumbnail>
          </ng-template>
          <ng-template #large>
            <app-action-thumbnail [action]="actionCard" [cssCardHeight]="1"></app-action-thumbnail>
          </ng-template>
        </div>
      </ng-template>
    </div>
  </div>
</div>

остросюжетный thumbnail.component.ts

import { Component, OnInit, Input } from '@angular/core';

@Component({
  selector: 'app-action-thumbnail',
  templateUrl: './action-thumbnail.component.html',
  styleUrls: ['./action-thumbnail.component.css']
})
export class ActionThumbnailComponent implements OnInit {
  @Input() action: Imenuoption;

  @Input() cssCardHeight: number;


  constructor() {
   }

  ngOnInit() {
  }

}

действия thumbnail.component.html

<div *ngIf="cssCardHeight === 0;then small else large"></div>
<ng-template #large>
  <div class="flip-card card-long" [routerLink]="action.navURL" routerLinkActive="router-link-active">
    <div class="flip-card-inner text-center">

      <div class="flip-card-front card-long" style="padding:20%">
        <img class="img-responsive" [src]='action.imageURL' alt="Card image cap">
        <br />
        <h5 class="card-text" style="letter-spacing: 1px; color: black; font-size: 16px;">{{action.description}}</h5>
      </div>

      <div class="flip-card-back card-long">
        <div class="card-body">
          <h3 class="card-title" style="padding: 3%;">{{action.description}}</h3>
          <h5 class="card-text">Description for this option goes here.</h5>
        </div>
      </div>

    </div>
  </div>

</ng-template>

<ng-template #small>
  <div class="flip-card card-small" [routerLink]="action.navURL" routerLinkActive="router-link-active">
    <div class="flip-card-inner text-center">

      <div class="flip-card-front card-small" style="padding:20%">
        <img class="img-responsive" [src]='action.imageURL' alt="Card image cap">
        <br />
        <h5 class="card-text" style="letter-spacing: 1px; color: black; font-size: 16px;">{{action.description}}</h5>
      </div>

      <div class="flip-card-back card-small">
        <div class="card-body">
          <h3 class="card-title" style="padding: 3%;">{{action.description}}</h3>
          <h5 class="card-text">Description for this option goes here.</h5>
        </div>
      </div>

    </div>
  </div>

</ng-template>

router.ts

const routes: Routes = [
  { path: '', redirectTo: 'home', pathMatch: 'full'},
  {
    path: 'home',
    component: ActionsListComponent,
    data : {
       breadcrumb : 'Home'
    },
    children: [
      {
      path: 'settings',
      component: ActionsListComponent,
      data: {
        breadcrumb: 'Settings',
        imageURL: './assets/images/settings.png'
      },
      children: [
      {
        path: 'sub-option1',
        component: OP1,
        data: {
          breadcrumb: 'Option 1',
          imageURL: './assets/images/o1.png'
        }
      },
      {
        path: 'sub-option2',
        component: Op2,
        data: {
          breadcrumb: 'Option 2',
          imageURL: './assets/images/o2.png'
        }
      }]
    },
    {
      path: 'o1',
      component: Option1,
      data: {
        breadcrumb: 'option 1'
      }
    },
    {
      path: 'o2',
      component: Option2,
      data: {
        breadcrumb: 'option 2'
      }
    },
    {
      path: 'o3',
      component: Option3,
      data: {
        breadcrumb: 'option 3' 
     }
    }]
  }
];

@NgModule({
  imports: [RouterModule.forRoot(routes)],
  exports: [RouterModule]
})

export class PMRoutingModule { }

Мой вопрос,

С вышеупомянутой структурой я не могу решить, где разместить <router-outlet>, чтобы загрузить соответствующие подопции или Функции.

...