ng2-file-upload icon indicating copy to clipboard operation
ng2-file-upload copied to clipboard

Image preview directive

Open BojanKogoj opened this issue 8 years ago • 28 comments

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

  • Add reference to ngModule
  • Use it like this
<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>
  • Will be displayed something like this (make sure to set sizes with css)

screen shot 2016-10-24 at 14 59 53

BojanKogoj avatar Oct 24 '16 13:10 BojanKogoj

+1

atais avatar Dec 02 '16 10:12 atais

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

Sathishchary avatar Dec 28 '16 14:12 Sathishchary

+1

rainstormza avatar Feb 06 '17 03:02 rainstormza

Thank you. It works like magic.

edmondtm avatar May 19 '17 12:05 edmondtm

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?

vlaco avatar Jun 29 '17 10:06 vlaco

Thank you @BojanKogoj, your solution works very well!

matheusdavidson avatar Sep 11 '17 16:09 matheusdavidson

Will this be integrated into the plugin at some point?

tobisinghania avatar Oct 13 '17 15:10 tobisinghania

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

adrianfaciu avatar Oct 22 '17 09:10 adrianfaciu

Hi can we preview the pdf file ?

AngularTx avatar Nov 11 '17 08:11 AngularTx

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.

vlaco avatar Nov 13 '17 09:11 vlaco

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

GPNandhini avatar Feb 26 '18 10:02 GPNandhini

@Pushpanandhini you most probably forgot to import Directive.

BojanKogoj avatar Feb 26 '18 10:02 BojanKogoj

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

GPNandhini avatar Feb 28 '18 07:02 GPNandhini

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';

Sathishchary avatar Feb 28 '18 08:02 Sathishchary

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>

isabelatelles avatar Mar 09 '18 21:03 isabelatelles

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

shakesBeardZ avatar Mar 13 '18 23:03 shakesBeardZ

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

erperejildo avatar Apr 17 '18 11:04 erperejildo

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:

  • *ngIf="item?._file.type === 'application/pdf'" in <object>
  • *ngIf="item?._file.type.startsWith('image')" for <img>

JulianSalomon avatar Apr 26 '18 15:04 JulianSalomon

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

wellingtonfoz avatar May 19 '18 07:05 wellingtonfoz

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

bdebon avatar Mar 18 '19 09:03 bdebon

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

patelmurtuza avatar Nov 22 '19 15:11 patelmurtuza

it works awsome with ng2FileSelect

patelmurtuza avatar Nov 22 '19 15:11 patelmurtuza

Muchas gracias! Thank very much! @BojanKogoj

canalrubi avatar Aug 22 '22 17:08 canalrubi

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>

timgavin avatar Aug 20 '23 18:08 timgavin

@timgavin have you added directive to the image?

BojanKogoj avatar Aug 20 '23 18:08 BojanKogoj

@timgavin have you added directive to the image?

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

timgavin avatar Aug 20 '23 19:08 timgavin

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

BojanKogoj avatar Aug 20 '23 20:08 BojanKogoj

@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],
   ...

timgavin avatar Aug 20 '23 21:08 timgavin