valor-software / ng2-file-upload

Easy to use Angular components for files upload
http://valor-software.github.io/ng2-file-upload/
MIT License
1.91k stars 662 forks source link

Image preview directive #461

Open BojanKogoj opened 8 years ago

BojanKogoj commented 8 years ago

I've been missing image preview with this library, so I made my own. Unlike #368 solution multiple images can be previewed. It's not perfect (doesn't detect if it's not an image), but if @valorkin thinks this could be somehow included I'm up for it. Should temporarily solve #294

image-preview.directive.ts

import { Directive, ElementRef, Input, Renderer, OnChanges, SimpleChanges } from '@angular/core';

@Directive({ selector: 'img[imgPreview]' })

export class ImagePreview {

    @Input() image: any;

    constructor(private el: ElementRef, private renderer: Renderer) { }

    ngOnChanges(changes: SimpleChanges) {

        let reader = new FileReader();
        let el = this.el;

        reader.onloadend = function (e) {
            el.nativeElement.src = reader.result;
        };

        if (this.image) {
            return reader.readAsDataURL(this.image);
        }

    }

}

Example usage

<div *ngFor="let item of uploader.queue" class="media">
    <div class="media-left">
        <img src="" imgPreview [image]="item?._file" class="media-object" />
    </div>
    <div class="media-body">
        <p>{{ item?.file?.name }}</p>
    </div>
</div>

screen shot 2016-10-24 at 14 59 53

atais commented 7 years ago

+1

Sathishchary commented 7 years ago

Can any one tried how to show the video preview .I need to show the preview of a video before it is uploaded.? thanks

rainstormza commented 7 years ago

+1

edmondtm commented 7 years ago

Thank you. It works like magic.

vlaco commented 7 years ago

Thanks! I used this for image preview before upload. But does anyone have an idea how to show preview in case the user wants to upload a pdf file?

matheusdavidson commented 7 years ago

Thank you @BojanKogoj, your solution works very well!

tobisinghania commented 7 years ago

Will this be integrated into the plugin at some point?

adrianfaciu commented 7 years ago

There is no open pull request with this. If one is provided it will be investigated and probably merged.

AngularTx commented 6 years ago

Hi can we preview the pdf file ?

vlaco commented 6 years ago

I made a workaround so that it check file type too, if the file is pdf it shows an iframe element, and if its any other file format (png, jpg, jpeg) it shows an img element.

GPNandhini commented 6 years ago

Hi, If i am using this code getting error , please find the below bold lines what we getting error

Can't bind to 'image' since it isn't a known property of 'img'. "<img src="" imgPreview [ERROR ->][image]="item?._file" class="media-object" />

Please help on this to resolved

BojanKogoj commented 6 years ago

@Pushpanandhini you most probably forgot to import Directive.

GPNandhini commented 6 years ago

@BojanKogoj , thank you image preview working .. Anyone have idea to preview the Video, Doc related files uploading?

Sathishchary commented 6 years ago

for video preview, use like this,

<video id="my-video" controls preload="auto" width="250" height="150">
  <source [src]='videoPreviewPath' type='video/mp4'>
</video>

component: videoPreviewPath = 'http://vjs.zencdn.net/v/oceans.mp4';

isabelatelles commented 6 years ago

I've done some modifications to detect if it is an image or a pdf file. It's pretty simple and you can easily adjust to your preferences of file type.

image-preview.directive.ts

import { Directive, ElementRef, Input, Renderer, OnChanges, SimpleChanges } from '@angular/core';

@Directive({ selector: '[imgPreview]' })

export class ImagePreviewDirective {

    @Input() private media: any;
    @Input() private type: any;

    constructor(private el: ElementRef, private renderer: Renderer) { }

    ngOnChanges(changes: SimpleChanges) {

        let reader = new FileReader();
        let el = this.el;

        if (this.type === 'application/pdf') {
            reader.onloadend = function (e) {
                el.nativeElement.data = reader.result;
            };
        } else if (this.type.split('/')[0] === 'image') {
            reader.onloadend = function (e) {
                el.nativeElement.src = reader.result;
            };
        }

        if (this.media) {
            return reader.readAsDataURL(this.media);
        }

    }
}

image-preview.component.ts

import { Component, OnInit } from '@angular/core';
import { ImageService } from '../shared/image.service';

@Component({
  selector: 'img-preview',
  templateUrl: './img-preview.component.html',
  styleUrls: ['./img-preview.component.scss']
})

export class ImgPreviewComponent implements OnInit {
  uploader: any;
  file: any;
  type: string;

  constructor(private imageService: ImageService) {
  }

  ngOnInit() {
    this.uploader = this.imageService.uploader.queue[0];
    this.file = this.imageService.uploader.queue[0]._file;
    if (this.imageService.uploader.queue[0].file.type === 'application/pdf')
      this.type = 'application/pdf';
    else if (this.imageService.uploader.queue[0].file.type.split('/')[0] === 'image')
      this.type = 'image';
  }
}

Example usage

<img *ngIf="type === 'image'"
          src="" imgPreview [media]="file" [type]="type"
          class="image">
<object *ngIf="type === 'application/pdf'"
            data="" imgPreview [media]="file" [type]="type"
            type="application/pdf" class="image-pdf"></object>
shakesBeardZ commented 6 years ago

@isabelatelles Like your implementation , tried it it's working thankxxxx

erperejildo commented 6 years ago

Thanks to @BojanKogoj and to @isabelatelles for these awesome directives

JulianSalomon commented 6 years ago

Thanks for the implementation @BojanKogoj and the improvements @isabelatelles.

I made some modifications that makes the code more clean:

  1. Renderer is not used, can be removed.
  2. If you get the File object, you don't need the type too, this can be retrieved with the object.
  3. Is unnecessary to make the return.
  4. String have the method startsWith(), then the split can be replaced with this.
  5. Validation of existent file should be done at start (If not, get the type of the file will throw an error).

media-preview.directive.ts

import { Directive, ElementRef, Input, Renderer, OnChanges, SimpleChanges } from '@angular/core';

@Directive({ selector: '[mediaPreview]' })

export class MediaPreviewDirective implements OnChanges {
  @Input() private media: File;

  constructor(private el: ElementRef) { }

  ngOnChanges(changes: SimpleChanges) {
    if (!this.media) {
      return;
    }
    const reader = new FileReader();
    const el = this.el;
    if (this.media.type === 'application/pdf') {
      reader.onloadend = () => el.nativeElement.data = reader.result;
    } else if (this.media.type.startsWith('image')) {
      reader.onloadend = () => el.nativeElement.src = reader.result;
    }
    reader.readAsDataURL(this.media);
  }
}

Usage

<div *ngFor="let item of uploader.queue" class="media">
    <div class="media-left">
        <!-- Image --><!-- Both of the two next lines produce the same result -->
        <img src mediaPreview [media]="item?._file" class="media-object" />
        <img src mediaPreview [media]="item?.file?.rawFile" class="media-object" />
        <!-- PDF -->
        <object data mediaPreview [media]="item._file" class="image-pdf"></object>
    </div>
</div>

Note: If you want include the preview of both (Image and PDF), you can add *ngIf statement as follows:

wellingtonfoz commented 6 years ago

Thank you so much! You saved me!!!!

bdebon commented 5 years ago

@JulianSalomon and @isabelatelles thanks for sharing these valuable improvements! It works like a charm.

patelmurtuza commented 4 years ago

@BojanKogoj, I was looking for this from long time, finally got it. highly appreciate. thanks a lot

patelmurtuza commented 4 years ago

it works awsome with ng2FileSelect

canalrubi commented 2 years ago

Muchas gracias! Thank very much! @BojanKogoj

timgavin commented 1 year ago

Followed @BojanKogoj 's OP and am receiving this error

NG0303: Can't bind to 'image' since it isn't a known property of 'img' (used in the 'UserPage' component template)

Any ideas on how to fix this?

Edit: I should have added some code smh

The Directive

import {Directive, ElementRef, Input, OnChanges, SimpleChanges} from '@angular/core';

@Directive({
    selector: '[appImagePreview]'
})
export class ImagePreviewDirective implements OnChanges {

    @Input() image: any;

    constructor(private el: ElementRef) {
    }

    ngOnChanges(changes: SimpleChanges) {

        let reader = new FileReader();
        let el = this.el;

        reader.onloadend = function (e) {
            el.nativeElement.src = reader.result;
        };

        if (this.image) {
            return reader.readAsDataURL(this.image);
        }

    }
}
<ion-item *ngFor="let item of uploader.queue" class="ion-no-padding">
    <div class="flex items-center justify-between">
        <ion-label>
            <fa-icon (click)="item.remove()" [icon]="faCircleXmark" class="fa-fw text-red-500 cursor-pointer"></fa-icon>
                {{ item?.file?.name }}
          </ion-label>
          <img src="" appImagePreview [image]="item?._file" alt="">
      </div>
</ion-item>
BojanKogoj commented 1 year ago

@timgavin have you added directive to the image?

timgavin commented 1 year ago

@timgavin have you added directive to the image?

Apologies, I should have included code. I've updated my post.

BojanKogoj commented 1 year ago

@timgavin Have you added it to declarations, or imports if you're using standalone components (and set standalone: true)?

timgavin commented 1 year ago

@timgavin Have you added it to declarations, or imports if you're using standalone components (and set standalone: true)?

I'm not using standalone components, and it's under declarations in my app.module.ts file

import { ImagePreviewDirective } from './directives/image-preview.directive';

@NgModule({
  declarations: [AppComponent, ImagePreviewDirective],
   ...