Hi friends, In today's post I will provide a lightning web component example that helps you to upload and preview image on record level. Image uploaded through this component stored in file(Content Document) object. so let's get started.

Upload and preview image in lightning web component

This component has dual functionality once for upload image and second for replace uploaded image, sounds interesting...so let's implement the functionality using lwc.

ImageUploaderHandler.apxc

 public inherited sharing class ImageUploaderHandler {    
@AuraEnabled
public static ContentVersion saveFile(Id recordId, String strFileName, String base64Data) {
base64Data = EncodingUtil.urlDecode(base64Data, 'UTF-8');
ContentVersion cv = new ContentVersion();
cv.Title = strFileName;
cv.PathOnClient = '/' + strFileName;
cv.FirstPublishLocationId = recordId;
cv.VersionData = EncodingUtil.base64Decode(base64Data);
cv.IsMajorVersion = true;
insert cv;
return cv;
}

@AuraEnabled
public static String setImageUrl(Id recordId){
list<id> lstConDocs = new list<id>();
for(ContentDocumentLink cntLink : [Select Id, ContentDocumentId From ContentDocumentLink Where LinkedEntityId =:recordId]) {
lstConDocs.add(cntLink.ContentDocumentId);
}
if(!lstConDocs.isEmpty()) {
ContentDistribution cdl = new ContentDistribution();
cdl.ContentVersionId = [SELECT Id, Title, ContentDocumentId FROM ContentVersion WHERE ContentDocumentId IN :lstConDocs LIMIT 1].Id;
cdl.Name = 'PublicShare';
insert cdl;
return [SELECT DistributionPublicUrl, ContentDownloadUrl FROM ContentDistribution WHERE Id = :cdl.Id LIMIT 1].ContentDownloadUrl;
}
else {
return null;
}
}

@AuraEnabled
public static void deleteFiles(Id recordId){
list<id> lstConDocs = new list<id>();
for(ContentDocumentLink cntLink : [Select Id, ContentDocumentId From ContentDocumentLink Where LinkedEntityId =:recordId]) {
lstConDocs.add(cntLink.ContentDocumentId);
}
if(!lstConDocs.isEmpty()) {
delete [SELECT Id FROM ContentDocument WHERE id IN:lstConDocs];
}
}
}
ImageUploaderLWC.html
  <template>
<div class="slds-box">
<div class="slds-box slds-grid slds-gutters">
<div class="slds-col" style="border-right:1px solid #ccc">
<lightning-card title="Upload Image" icon-name="utility:image">
<div>
<lightning-input label="" accept="image/png,image/jpeg" name="file uploader" onchange={handleFilesChange} type="file">
</lightning-input>
</div><br />
<div class="slds-text-body_small slds-text-color_error">{fileName}
<template if:true={showLoadingSpinner}>
<lightning-spinner alternative-text="Uploading......" size="medium"></lightning-spinner>
</template>
</div><br />
<div>
<template if:false={data}>
<lightning-button class="slds-m-top--medium" label="Upload Image" onclick={handleSave}
variant="brand" disabled={isTrue}></lightning-button>
</template>
<template if:true={data}>
<lightning-button class="slds-m-top--medium" label="Replace Image" onclick={handleReplace}
variant="brand" disabled={isTrue}></lightning-button>
</template>

</div>
<br /><br />
</lightning-card>
</div>
<div class="slds-col">
<lightning-card title="Preview of Uploaded Image" icon-name="utility:image">
<div style="width: auto;">
<template if:false={data}>
<i class="slds-text-color_error">No image uploaded!</i>
</template>
<template if:true={data}>
<img src={data} width="150">
</template>
</div>
</lightning-card>
</div>
</div>
</div>
</template>
ImageUploaderLWC.js
 import { LightningElement, track, api } from 'lwc';
import saveFile from '@salesforce/apex/ImageUploaderHandler.saveFile';
import setImageUrl from '@salesforce/apex/ImageUploaderHandler.setImageUrl';
import deleteFiles from '@salesforce/apex/ImageUploaderHandler.deleteFiles';
import { ShowToastEvent } from 'lightning/platformShowToastEvent';

export default class ImageUploaderLWC extends LightningElement {
@api recordId;
@track data;
@track fileName = '';
@track showLoadingSpinner = false;
@track isTrue = false;
filesUploaded = [];
file;
fileContents;
fileReader;
content;
MAX_FILE_SIZE = 1500000;

connectedCallback() {
this.populateImageUrl();
}

handleFilesChange(event) {
this.fileName = '';
if (event.target.files.length > 0) {
if (event.target.files[0].type != 'image/jpeg' && event.target.files[0].type != 'image/png') {
this.fileName = 'Invalid file type!!';
this.isTrue = true;
}
else {
this.isTrue = false;
this.filesUploaded = event.target.files;
this.fileName = event.target.files[0].name;
}
}
}

handleSave() {
if (this.filesUploaded.length > 0) {
this.uploadHelper();
}
else {
this.fileName = 'Please select file to upload!!';
}
}

handleReplace() {
if (this.filesUploaded.length > 0) {
deleteFiles({ recordId: this.recordId })
.then(data => {
console.log(data);
this.uploadHelper();
})
.catch(error => {
this.dispatchEvent(
new ShowToastEvent({
title: 'Error!!',
message: error.message,
variant: 'error',
}),
);
});
}
else {
this.fileName = 'Please select file to upload!!';
}
}

uploadHelper() {
this.file = this.filesUploaded[0];
if (this.file.size > this.MAX_FILE_SIZE) {
this.dispatchEvent(
new ShowToastEvent({
title: 'Error',
message: 'File Size is to long',
variant: 'error',
}),
);
return;
}
this.isTrue = true;
this.showLoadingSpinner = true;
// create a FileReader object
this.fileReader = new FileReader();
// set onload function of FileReader object
this.fileReader.onloadend = (() => {
this.fileContents = this.fileReader.result;
let base64 = 'base64,';
this.content = this.fileContents.indexOf(base64) + base64.length;
this.fileContents = this.fileContents.substring(this.content);
this.saveToFile();
});
this.fileReader.readAsDataURL(this.file);
}

// Calling apex class to insert the file
saveToFile() {
saveFile({ recordId: this.recordId, strFileName: this.file.name, base64Data: encodeURIComponent(this.fileContents) })
.then(result => {
window.console.log('result ' + result);
this.populateImageUrl();
this.fileName = this.fileName + ' - Uploaded Successfully';
this.isTrue = false;
this.showLoadingSpinner = false;
this.filesUploaded = [];
this.dispatchEvent(
new ShowToastEvent({
title: 'Success!!',
message: this.file.name + ' - Uploaded Successfully!!!',
variant: 'success',
}),
);
eval("$A.get('e.force:refreshView').fire();");
})
.catch(error => {
this.dispatchEvent(
new ShowToastEvent({
title: 'Error while uploading File',
message: error.message,
variant: 'error',
}),
);
});
}

//Getting releated files of the current record
populateImageUrl() {
setImageUrl({ recordId: this.recordId }).then(data => {
this.data = data;
console.log(data);
}).catch(error => {
this.dispatchEvent(
new ShowToastEvent({
title: 'Error!!',
message: error.message,
variant: 'error',
}),
);
});
}
}
ImageUploaderLWC.js-meta.xml
 <?xml version="1.0"?>
<LightningComponentBundle xmlns="http://soap.sforce.com/2006/04/metadata">
<apiVersion>51.0</apiVersion>
<isExposed>true</isExposed>
<masterLabel>Image Uploader</masterLabel>
<targets>
<target>lightning__RecordPage</target>
</targets>
</LightningComponentBundle>

Note: Please upload this component to any object record detail page to see the preview and test functionality.

Output:

 

Hope you like this post, for any feedback or suggestions please feel free to comment. I would appreciate your feedback and suggestions.
Thank you.