Angular 2 - (SystemJS) неожиданная директива 'ViewerComponent' импортированная модулем 'GalleryModule'


Я получаю следующую ошибку, не знаю, что делать:

(SystemJS) неожиданная директива ViewerComponent, импортированная модулем GalleryModule

Спасибо за любую помощь, связанную с тем, что может быть причиной ошибки. В главном приложении он импортирует модуль галереи. Галерея компонента и компонента просмотра, как ребенок.

Компонент Галереи:

import {Component, NgZone, ViewChild, ElementRef} from '@angular/core';
import {Http, Response} from '@angular/http';
import { ViewerComponent } from '../viewer/viewer.component';
import 'rxjs/Rx';

interface IImage {
  url: string;
  thumbnail: string;
  date: string;
  width: number;
  height: number;
}

@Component({
  selector: 'sd-gallery',
  templateUrl: 'gallery.component.html',
  styleUrls: ['gallery.component.css']
})
export class GalleryComponent {;
  @ViewChild('galleryContainer') galleryContainer: ElementRef;
  @ViewChild('asyncLoadingContainer') asyncLoadingContainer: ElementRef;

  thumbnailBasePath = 'assets/img/gallery/preview_xxs/';
  currentIdx: number = 0;
  galleryBasePath: string = 'assets/img/gallery/';
  showBig: boolean = false;
  images: any[] = [{ url: '' }];
  gallery: any[] = [];
  imgIterations = 1;
  allImagesLoaded = false;

  // TypeScript public modifiers
  constructor(private _ngZone: NgZone, private http: Http) {

  }

  private ngAfterContentInit() {
    this.fetchDataAndRender();
  }

  private fetchDataAndRender() {
    this.http.get(this.galleryBasePath + 'data.json')
      .map((res: Response) => res.json())
      .subscribe(
      data => {
        this.images = data;
        this.render();
      },
      err => console.error(err),
      () => undefined);
  }

  private render() {
    let tempRow = [this.images[0]];
    let rowIndex = 0;
    let i = 0;

    for (i; i < this.imgIterations && i < this.images.length; i++) {
      while (this.images[i + 1] && this.shouldAddCandidate(tempRow, this.images[i + 1])) {
        i++;
      }
      if (this.images[i + 1]) {
        tempRow.pop();
      }
      this.gallery[rowIndex++] = tempRow;

      tempRow = [this.images[i + 1]];
    }

    this.scaleGallery();

    if (i >= this.images.length) {
      this.allImagesLoaded = true;
    }
    else {
      this.checkForAsyncReload();
    }
  }

  private shouldAddCandidate(imgRow: IImage[], candidate: IImage): boolean {
    let oldDifference = this.calcIdealHeight() - this.calcRowHeight(imgRow);
    imgRow.push(candidate);
    let newDifference = this.calcIdealHeight() - this.calcRowHeight(imgRow);

    return Math.abs(oldDifference) > Math.abs(newDifference);
  }

  private calcRowHeight(imgRow: IImage[]) {
    let xsum = this.calcOriginalRowWidth(imgRow);

    let ratio = this.getGalleryWidth() / xsum;
    let rowHeight = imgRow[0].height * ratio;

    return rowHeight;
  }

  private scaleGallery() {
    this.gallery.forEach((imgRow) => {
      let xsum = this.calcOriginalRowWidth(imgRow);

      if (imgRow != this.gallery[this.gallery.length - 1]) {
        let ratio = this.getGalleryWidth() / xsum;

        imgRow.forEach((img: any) => {
          img.width = img.width * ratio;
          img.height = img.height * ratio;
        })
      }
    })
  }

  private calcOriginalRowWidth(imgRow: IImage[]) {
    let xsum = 0;
    imgRow.forEach((img) => {
      let individualRatio = this.calcIdealHeight() / img.height;
      img.width = img.width * individualRatio;
      img.height = this.calcIdealHeight();
      xsum += img.width + 1;
    });

    return xsum;
  }

  private calcIdealHeight() {
      return (this.getGalleryWidth() / 8) + 70;
  }

  private openImageViewer(img: any) {
    this.showBig = undefined;
    this.showBig = true;
    this.currentIdx = this.images.indexOf(img);
  }

  private getGalleryWidth() {
    if (this.galleryContainer.nativeElement.clientWidth === 0) {
      // IE11
      return this.galleryContainer.nativeElement.scrollWidth;
    }
    return this.galleryContainer.nativeElement.clientWidth;
  }

  private checkForAsyncReload() {
    if (!this.allImagesLoaded) {
      var loadingDiv: any = this.asyncLoadingContainer.nativeElement;

      var elmTop = loadingDiv.getBoundingClientRect().top;
      var elmBottom = loadingDiv.getBoundingClientRect().bottom;

      var isVisible = (elmTop >= 0) && (elmBottom <= window.innerHeight);

      if (isVisible) {
        this.imgIterations += 5;
        this.fetchDataAndRender();
      }
    }
  }

  private onClose() {
    this.showBig = false;
  }

  private onResize() {
    this.render();
  }
}

Модуль Галереи:

import { BrowserModule } from '@angular/platform-browser';
import { NgModule } from '@angular/core';
import { FormsModule } from '@angular/forms';
import { HttpModule } from '@angular/http';

import { ViewerComponent } from '../viewer/viewer.component';
import { GalleryComponent } from './gallery.component';

@NgModule({
  imports: [BrowserModule, FormsModule, HttpModule, ViewerComponent],
  declarations: [GalleryComponent],
  exports: [GalleryModule],
  providers: []
})
export class GalleryModule { }

Просмотр HTML:

<div class="outerContainer" (window:resize)="onResize($event)" [hidden]="!showViewer">
  <img [ngClass]="{'activeArrow': leftArrowActive}" class="arrow left" [src]="arrows[0]" (click)="navigate(-1, false)" [hidden]="!showViewer || !leftArrowVisible" />
  <img [ngClass]="{'activeArrow': rightArrowActive}" class="arrow right" [src]="arrows[1]" (click)="navigate(1, false)" [hidden]="!showViewer || !rightArrowVisible" />
  <div class="buttonContainer" [hidden]="!showViewer">
    <span class="action fullsize" (click)="openFullsize()" [hidden]="!showViewer">100%</span>
    <img class="action close" src="assets/img/icon/close.svg" (click)="closeViewer()" [hidden]="!showViewer" />
  </div>
  <div class="imageContainer" (click)="showNavigationArrows()" (swipeleft)="navigate(1, true)" (swiperight)="navigate(-1, true)" [hidden]="!showViewer">
    <img class="image" [src]="previewImagePath" [hidden]="!showViewer" />
  </div>
</div>

Компонент Просмотра:

import {Component, NgZone, ViewChild, ElementRef, Input, Output, EventEmitter} from '@angular/core';
import {Http, Response} from '@angular/http';
import 'rxjs/Rx';

interface IImage {
  url: string;
  thumbnail: string;
  date: string;
  width: number;
  height: number;
}

@Component({
  selector: 'sd-viewer',
  templateUrl: 'viewer.component.html',
  styleUrls: ['viewer.component.css']
})
//  host: {
 //   '(document:keydown)': 'onKeydown($event)',
//  }
export class ViewerComponent {
  @Input() images: any[];
  @Input() currentIdx: number;
  @Input() showViewer: boolean;
  @Output() onClose = new EventEmitter<boolean>();

  arrows: string[] = ['assets/img/icon/left.svg', 'assets/img/icon/right.svg'];
  leftArrowActive: boolean = true;
  rightArrowActive: boolean = true;
  leftArrowVisible: boolean = true;
  rightArrowVisible: boolean = true;
  previewImagePath = '';

  // TypeScript public modifiers
  constructor(private _ngZone: NgZone, private http: Http) {
  }

  ngOnChanges(changes: any) {
    if (this.images[this.currentIdx].name) {
      this.updatePreviewImage();
    }
  }

  ngAfterContentInit() {
  }

  onKeydown(event: KeyboardEvent) {
    let prevent = [37, 39, 27]
      .find(no => no === event.keyCode);
    if (prevent) event.preventDefault();

    switch (prevent) {
      case 37:
        // navigate left
        this.navigate(-1, false);
        break;
      case 39:
        // navigate right
        this.navigate(1, false);
        break;
      case 27:
        // esc
        this.closeViewer();
        break;
    }
  }

  updateArrowActivation() {
    if (this.currentIdx <= 0) {
      this.leftArrowActive = false;
    }
    else {
      this.leftArrowActive = true;
    }
    if (this.currentIdx >= this.images.length - 1) {
      this.rightArrowActive = false;
    }
    else {
      this.rightArrowActive = true;
    }
  }

  /**
  * direction (-1: left, 1: right)
  * swipe (user swiped)
  */
  navigate(direction : number, swipe : boolean) {
    if ((direction === 1 && this.currentIdx < this.images.length - 1) ||
       (direction === -1 && this.currentIdx > 0)) {
      // increases or decreases the counter
      this.currentIdx += direction;
      if (swipe) {
        this.hideNavigationArrows();
      }
      else {
        this.updateArrowActivation();
        this.showNavigationArrows();
      }
      this.updatePreviewImage();
    }
  }

  hideNavigationArrows() {
    this.leftArrowVisible = false;
    this.rightArrowVisible = false;
  }

  showNavigationArrows() {
    this.leftArrowVisible = true;
    this.rightArrowVisible = true;
  }

  openFullsize() {
    window.location.href = 'assets/img/gallery/raw/' + this.images[this.currentIdx].name;
  }

  private closeViewer() {
    this.showViewer = false;
    this.onClose.emit(false);
  }

  private updatePreviewImage() {
    let height = window.innerHeight;
    let basePath = 'assets/img/gallery/';

    if (height <= 375) {
      basePath += 'preview_xxs/';
    } else if (height <= 768) {
      basePath += 'preview_xs/';
    } else if (height <= 1080) {
      basePath += 'preview_s/';
    } else if (height <= 1600) {
      basePath += 'preview_m/';
    } else if (height <= 2160) {
      basePath += 'preview_l/';
    } else if (height <= 2880) {
      basePath += 'preview_xl/';
    } else {
      basePath += 'raw';
    }

    this.previewImagePath = basePath + this.images[this.currentIdx].name;
  }

  private onResize() {
    this.updatePreviewImage();
  }
}
1 7

1 ответ:

Переместить ViewerComponent из импорта GalleryModule в объявления. Только модули могут быть добавлены к импорту модуля. Компоненты, директивы и каналы размещаются в объявлениях модуля:

@NgModule({
  imports: [BrowserModule, FormsModule, HttpModule],
  declarations: [GalleryComponent, ViewerComponent],
  exports: [GalleryModule],
  providers: []
})

export class GalleryModule { }

Проверьте угловые 2 модуля для получения дополнительной информации.