samedi 27 juillet 2019

How to fix 'Template parse errors' in my angular 8 project?

I'm trying to add a multiple file uploader in my Angular 8 project and I have encountered this error in my browser console:

Error: Template parse errors:
Can't bind to 'file' since it isn't a known property of 'upload-task'.
1. If 'upload-task' is an Angular component and it has 'file' input, then verify that it is part of this module.
2. If 'upload-task' is a Web Component then add 'CUSTOM_ELEMENTS_SCHEMA' to the '@NgModule.schemas' of this component to suppress this message.
3. To allow any property add 'NO_ERRORS_SCHEMA' to the '@NgModule.schemas' of this component. ("
    <h3>Uploads</h3>
    <div *ngFor="let file of files">
      <upload-task [ERROR ->][file]="file"></upload-task>
    </div>
"): ng:///AppModule/DashboardComponent.html@56:23
'upload-task' is not a known element:
1. If 'upload-task' is an Angular component, then verify that it is part of this module.
2. If 'upload-task' is a Web Component then add 'CUSTOM_ELEMENTS_SCHEMA' to the '@NgModule.schemas' of this component to suppress this message. ("
    <h3>Uploads</h3>
    <div *ngFor="let file of files">
      [ERROR ->]<upload-task [file]="file"></upload-task>
    </div>

"): ng:///AppModule/DashboardComponent.html@56:10

I'm not very skilled in angular, I'm a beginner so I don't understand this error. I have the upload-task component created, I imported it in the app.module.ts. It seems as if I don't have the upload-task at all.

This is the dashboard.component.html where the drop zone should be

<!-- Upload videos -->
<div class="dropzone" 
   dropzone
   (hovered)="toggleHover($event)"
   (dropped)="onDrop($event)"
   [class.hovering]="isHovering">

   <h3>AngularFire Drop Zone</h3>
   <p>Drag and Drop a File</p>
</div>
<h3>Uploads</h3>
<div *ngFor="let file of files">
   <upload-task [file]="file"></upload-task>
</div>

This is what's in the dashboard.component.ts

import { Component, OnInit } from '@angular/core';
import { AuthService } from "../../../shared/services/auth.service"

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

  email:string;

  isHovering: boolean;

  files: File[] = [];

  toggleHover(event: boolean) {
    this.isHovering = event;
  }

  onDrop(files: FileList) {
    for (let i = 0; i < files.length; i++) {
        this.files.push(files.item(i));
    }
  }

  constructor( public authService: AuthService ) {
    this.authService.getUser().subscribe(user => this.email =  user.email);
  }

  ngOnInit() {
  }

}

upload-task.component.html

<div *ngIf="percentage | async as pct">
   <progress [value]="pct" max="100"></progress>
   %
</div>

<div *ngIf="snapshot | async as snap">

 of  

<div *ngIf="downloadURL as url">
   <h3>Results!</h3>
   <img [src]="url"><br>
   <a [href]="url" target="_blank" rel="noopener">Download Me!</a>
</div> 

<button (click)="task.pause()"  [disabled]="!isActive(snap)">Pause</button>
<button (click)="task.cancel()" [disabled]="!isActive(snap)">Cancel</button>
<button (click)="task.resume()" [disabled]="!(snap?.state === 'paused')">Resume</button>

</div>

upload-task.component.ts

import { Component, OnInit, Input, ChangeDetectorRef } from '@angular/core';
import { AngularFireStorage, AngularFireUploadTask } from '@angular/fire/storage';
import { AngularFirestore } from '@angular/fire/firestore';
import { Observable } from 'rxjs';
import { finalize, tap } from 'rxjs/operators';

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

@Input() file: File;

task: AngularFireUploadTask;

percentage: Observable<number>;
snapshot: Observable<any>;
downloadURL: string;

constructor(private storage: AngularFireStorage, private db: AngularFirestore) { }

ngOnInit() {
  this.startUpload();
}

startUpload() {

  // The storage path
  const path = `test/${Date.now()}_${this.file.name}`;

  // Reference to storage bucket
  const ref = this.storage.ref(path);

  // The main task
  this.task = this.storage.upload(path, this.file);

  // Progress monitoring
  this.percentage = this.task.percentageChanges();

  this.snapshot   = this.task.snapshotChanges().pipe(
    tap(console.log),
    // The file's download URL
    finalize( async() =>  {
      this.downloadURL = await ref.getDownloadURL().toPromise();

      this.db.collection('files').add( { downloadURL: this.downloadURL, path });
    }),
   );
}

 isActive(snapshot) {
  return snapshot.state === 'running' && snapshot.bytesTransferred < snapshot.totalBytes;
 }
}

I also created a directive, which receives the files, I'll add it as well, it's called dropzpne.directive.ts

import { Directive, HostListener, Output, EventEmitter } from '@angular/core';

/**
 * Directive class that receives files from the browser.
 * Customize the drag and drop API to meet specific needs.
 */
@Directive({
  selector: '[dropzone]'
})

export class DropzoneDirective {

   @Output() dropped =  new EventEmitter<FileList>();
   @Output() hovered =  new EventEmitter<boolean>();

   @HostListener('drop', ['$event'])
   onDrop($event) {
      $event.preventDefault();
      this.dropped.emit($event.dataTransfer.files);
      this.hovered.emit(false);
   }

   @HostListener('dragover', ['$event'])
   onDragOver($event) {
      $event.preventDefault();
      this.hovered.emit(true);
   }

   @HostListener('dragleave', ['$event'])
   onDragLeave($event) {
      $event.preventDefault();
      this.hovered.emit(false);
   }

   constructor() { }

}

I'm sorry for the overwhelming amount of info, I just wanted to be precise. Also, I have been following this tutorial.




2 commentaires: