Как избежать необходимости внедрения зависимостей для типов объединения в Component c -tor? - PullRequest
0 голосов
/ 05 февраля 2020

У меня есть два компонента (которые могут быть сделаны реализациями общего базового класса / интерфейса).

Автоматический механизм внедрения зависимостей c для конструкторов компонентов не работает для моего случая, когда общий дочерний элемент компонент этих двух компонентов должен иметь доступ к своему указанному c родительскому компоненту.

Что мне нужно сделать, чтобы по-прежнему иметь один тип подкомпонента для обоих родительских типов?

Исходный код

компонент просмотра часов

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

import { Clock } from "../clock";

import { ClocksFlowViewComponent } from "../clocks-flow-view/clocks-flow-view.component";
import { ClocksDataGridComponent } from '../clocks-data-grid/clocks-data-grid.component';

@Component({
  selector: 'app-clock-view',
  templateUrl: './clock-view.component.html',
  styleUrls: ['./clock-view.component.scss']
})
export class ClockViewComponent implements OnInit {

  @Input() clock: Clock;

  constructor(
    private parentCollectionView: ClocksFlowViewComponent
  ) { }

  ngOnInit() {

  }

  onClicked(c: Clock)
  {
    for (let c2 of this.parentCollectionView.clocks)
    {
      c2.selected = false;
    }

    c.selected = true;
  }
}

компонент сетки данных часов

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

import { Clock } from '../clock';
import { ClockService } from "../clock.service";

@Component({
  selector: 'app-clocks-data-grid',
  templateUrl: './clocks-data-grid.component.html',
  styleUrls: ['./clocks-data-grid.component.scss']
})
export class ClocksDataGridComponent implements OnInit {

  static selectedClock : Clock | null;
  clocks : Clock[];

  constructor(
    private clockService: ClockService
  ) {
  }

  ngOnInit() {
    this.getClocks();
  }

  getClocks(): void
  {
    this.clockService.getClocks()
      .subscribe(clocks => this.clocks = clocks);
  }

}

компонент просмотра часов

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

import { Clock } from '../clock';
import { ClockService } from "../clock.service";

@Component({
  selector: 'app-clocks-flow-view',
  templateUrl: './clocks-flow-view.component.html',
  styleUrls: ['./clocks-flow-view.component.scss']
})
export class ClocksFlowViewComponent implements OnInit {

  static selectedClock : Clock | null;
  clocks : Clock[];

  constructor(
    private clockService: ClockService
  ) {
  }

  ngOnInit() {
    this.getClocks();
  }

  getClocks(): void
  {
    this.clockService.getClocks()
      .subscribe(clocks => this.clocks = clocks);
  }
}

Шаблоны

В настоящее время шаблоны для сетки данных и представления потока одинаковы:

<div *ngFor="let clock of clocks">
    <app-clock-view [clock]="clock"></app-clock-view>
</div>

Но они будут отличаться.

Шаблон компонента просмотра часов:

<div class="clock-view" (click)="onClicked(clock)" [class.selected]="clock.selected">
    <h2>{{clock.id}}. {{clock.tag}}</h2>
    <textarea [(ngModel)]="clock.tag" placeholder="clock tag here" class="clock-tag-textarea"></textarea>
</div>

При посещении http://localhost: 4200 / data-grid я получаю эту ошибку в консоли Chrome:

core.js:38781 Angular is running in the development mode. Call enableProdMode() to enable the production mode.
ClocksDataGridComponent.html:4 ERROR NullInjectorError: StaticInjectorError(AppModule)[ClockViewComponent -> ClocksFlowViewComponent]: 
  StaticInjectorError(Platform: core)[ClockViewComponent -> ClocksFlowViewComponent]: 
    NullInjectorError: No provider for ClocksFlowViewComponent!
    at NullInjector.get (http://localhost:4200/vendor.js:39072:27)
    at resolveToken (http://localhost:4200/vendor.js:53990:24)
    at tryResolveToken (http://localhost:4200/vendor.js:53916:16)
    at StaticInjector.get (http://localhost:4200/vendor.js:53766:20)
    at resolveToken (http://localhost:4200/vendor.js:53990:24)
    at tryResolveToken (http://localhost:4200/vendor.js:53916:16)
    at StaticInjector.get (http://localhost:4200/vendor.js:53766:20)
    at resolveNgModuleDep (http://localhost:4200/vendor.js:64953:29)
    at NgModuleRef_.get (http://localhost:4200/vendor.js:66019:16)
    at resolveDep (http://localhost:4200/vendor.js:66550:45)
View_ClocksDataGridComponent_1 @ ClocksDataGridComponent.html:4
logError @ core.js:45546
handleError @ core.js:6066
(anonymous) @ core.js:41058
invoke @ zone-evergreen.js:359
run @ zone-evergreen.js:124
runOutsideAngular @ core.js:39572
tick @ core.js:41055
(anonymous) @ core.js:40893
invoke @ zone-evergreen.js:359
onInvoke @ core.js:39699
invoke @ zone-evergreen.js:358
run @ zone-evergreen.js:124
run @ core.js:39511
next @ core.js:40890
schedulerFn @ core.js:35336
__tryOrUnsub @ Subscriber.js:185
next @ Subscriber.js:124
_next @ Subscriber.js:72
next @ Subscriber.js:49
next @ Subject.js:39
emit @ core.js:35298
checkStable @ core.js:39642
onHasTask @ core.js:39719
hasTask @ zone-evergreen.js:411
_updateTaskCount @ zone-evergreen.js:431
_updateTaskCount @ zone-evergreen.js:264
runTask @ zone-evergreen.js:185
drainMicroTaskQueue @ zone-evergreen.js:559
Promise.then (async)
scheduleMicroTask @ zone-evergreen.js:542
scheduleTask @ zone-evergreen.js:381
scheduleTask @ zone-evergreen.js:211
scheduleMicroTask @ zone-evergreen.js:231
scheduleResolveOrReject @ zone-evergreen.js:845
then @ zone-evergreen.js:955
bootstrapModule @ core.js:40600
./src/main.ts @ main.ts:11
__webpack_require__ @ bootstrap:79
0 @ main.ts:18
__webpack_require__ @ bootstrap:79
checkDeferredModules @ bootstrap:45
webpackJsonpCallback @ bootstrap:32
(anonymous) @ main.js:1
ClocksDataGridComponent.html:4 ERROR CONTEXT DebugContext_ {view: {…}, nodeIndex: 2, nodeDef: {…}, elDef: {…}, elView: {…}}
View_ClocksDataGridComponent_1 @ ClocksDataGridComponent.html:4
logError @ core.js:45546
handleError @ core.js:6071
(anonymous) @ core.js:41058
invoke @ zone-evergreen.js:359
run @ zone-evergreen.js:124
runOutsideAngular @ core.js:39572
tick @ core.js:41055
(anonymous) @ core.js:40893
invoke @ zone-evergreen.js:359
onInvoke @ core.js:39699
invoke @ zone-evergreen.js:358
run @ zone-evergreen.js:124
run @ core.js:39511
next @ core.js:40890
schedulerFn @ core.js:35336
__tryOrUnsub @ Subscriber.js:185
next @ Subscriber.js:124
_next @ Subscriber.js:72
next @ Subscriber.js:49
next @ Subject.js:39
emit @ core.js:35298
checkStable @ core.js:39642
onHasTask @ core.js:39719
hasTask @ zone-evergreen.js:411
_updateTaskCount @ zone-evergreen.js:431
_updateTaskCount @ zone-evergreen.js:264
runTask @ zone-evergreen.js:185
drainMicroTaskQueue @ zone-evergreen.js:559
Promise.then (async)
scheduleMicroTask @ zone-evergreen.js:542
scheduleTask @ zone-evergreen.js:381
scheduleTask @ zone-evergreen.js:211
scheduleMicroTask @ zone-evergreen.js:231
scheduleResolveOrReject @ zone-evergreen.js:845
then @ zone-evergreen.js:955
bootstrapModule @ core.js:40600
./src/main.ts @ main.ts:11
__webpack_require__ @ bootstrap:79
0 @ main.ts:18
__webpack_require__ @ bootstrap:79
checkDeferredModules @ bootstrap:45
webpackJsonpCallback @ bootstrap:32
(anonymous) @ main.js:1
client:52 [WDS] Live Reloading enabled.

Проблема, вкратце выражается, что внедрение зависимости в конструкторы d oes не работает с типами union (в моем случае ClocksFlowViewComponent | ClocksDataGridComponent). Проблема в том, что если я добавляю тип объединения, он выдает ошибку времени выполнения, и если я ставлю два параметра, для одного он тоже не срабатывает с ошибкой времени выполнения, и я не знаю наиболее правильной альтернативы.

...
  constructor(
    private parentCollectionView: ClocksFlowViewComponent 
  ) { }
...

Репозиторий GitHub здесь .

Это мой первый день с Angular. Спасибо.

Обновление 1

Я пытаюсь достичь с помощью метода onClicked в компоненте clock-view. Я хочу знать, какой clock-view выбран. В будущем мне может понадобиться сложный механизм выбора (множественный выбор, Ctrl, Shift, прямоугольник с резинкой, щелчок мыши).

1 Ответ

1 голос
/ 05 февраля 2020

вы можете предоставить все компоненты вашего контейнера в виде некоторого токена (который будет одинаковым для всех возможных контейнеров), чтобы их потомки могли вводить их

const CONTAINER_TOKEN = new InjectionToken<ContainerInterface>('Container Token');
....
@Component({
...
providers: [{provide: CONTAINER_TOKEN, useExisting: ClocksFlowViewComponent }]
})
export class ClocksFlowViewComponent {
}
...
@Component({
...
providers: [{provide: CONTAINER_TOKEN, useExisting: ClocksDataGridComponent }]
})
export class ClocksDataGridComponent {
}
...
export class ClockViewComponent implements OnInit {

  @Input() clock: Clock;

  constructor(
    @Inject(CONTAINER_TOKEN ) private parentCollectionView: ContainerInterface
  ) { }

...