Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Angular 2 - (SystemJS) Unexpected directive 'ViewerComponent' imported by the module 'GalleryModule'

I am getting the following error, not sure what to do:

(SystemJS) Unexpected directive ViewerComponent imported by the module GalleryModule

Thanks for any help relating to what might be causing the error. In the main app it is importing the gallery module. The gallery component has the viewer component as a child.

Gallery Component:

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();
  }
}

Gallery Module:

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 { }

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

Viewer Component:

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();
  }
}
like image 476
Pete Avatar asked Oct 18 '16 13:10

Pete


1 Answers

Move ViewerComponent from GalleryModule's imports to declarations. Only modules can be added to module's imports. Components, directives and pipes are placed in module's declarations:

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

export class GalleryModule { }

Check Angular 2 Modules for more information.

like image 127
Stefan Svrkota Avatar answered Nov 19 '22 20:11

Stefan Svrkota