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 ответ:
Переместить
ViewerComponent
из импортаGalleryModule
в объявления. Только модули могут быть добавлены к импорту модуля. Компоненты, директивы и каналы размещаются в объявлениях модуля:@NgModule({ imports: [BrowserModule, FormsModule, HttpModule], declarations: [GalleryComponent, ViewerComponent], exports: [GalleryModule], providers: [] }) export class GalleryModule { }
Проверьте угловые 2 модуля для получения дополнительной информации.