How To Add Image Upload Control In React Quill Rich Text Editor

Introduction

 
In this article, we will learn how can we allow users to upload images in a rich text editor in the SPFx web part.
 
When you copy and paste the image in React quill text editor, it will be pasted successfully and if you inspect this image from the developer tool of the browser you can see there will be a base64 string of images.
 
And when you save it, it will not be saved in the rich text column of your SharePoint list. Even only copy-paste in a rich text column in the list directly will also not save the image. SharePoint column will store the image in a rich text editor if the reference is of any SharePoint itself or any image URL which is accessible anonymously.
 
So, let’s see how can we achieve image upload functionality in the SPFx web part’s rich text editor control.
 
Follow the below steps to achieve this functionality:
 

Steps

 
Step 1
 
Upload package of the react quill using the below command:
  1. npm i react-quill   
Step 2
 
Import package in SPFx web part as below:
  1. import ReactQuill from 'react-quill';  
Step 3
 
Declare a global variable. This variable will be used as context for our rich text editor control.
  1. var quillObj: any;   
Step 4
 
Add react quill control in render method as below:
  1. <ReactQuill  
  2.               ref={(el) => {  
  3.                 quillObj = el;  
  4.               }}  
  5.               value={this.state.Description}  
  6.               modules={{  
  7.                 toolbar: {  
  8.                   container: [  
  9.                     [{ 'header': [1, 2, 3, 4, 5, 6, false] }],  
  10.                     ['bold''italic''underline'],  
  11.                     [{ 'list''ordered' }, { 'list''bullet' }],  
  12.                     [{ 'align': [] }],  
  13.                     ['link''image'],  
  14.                     ['clean'],  
  15.                     [{ 'color': [] }]  
  16.                   ],  
  17.                   handlers: {  
  18.                     image: this.imageHandler  
  19.                   }  
  20.                 },  
  21.                 table: true  
  22.               }}  
  23.               placeholder="Add a description of your event"  
  24.               onChange={(content, delta, source, editor) => this.onDescriptionChange(content, editor)}  
  25.               id="txtDescription"  
  26.             />    
  • In the above code, you can see ['link', 'image'] in the container options. When you add an Image in the container array, it will display the image upload icon in the rich text control as shown in the below screenshot.
 
Step 5
 
Now when clicks on the Image upload icon, we need to define which method should be called. So we need to define this method in handlers. So in control, we need to define handlers in the toolbar section: 
  1. handlers: {  
  2.    image: this.imageHandler  
  3. }  
Step 6
 
Now imageHandler method will have code as below,
  1. public async imageHandler() {  
  2.     const input = document.createElement('input');  
  3.   
  4.     input.setAttribute('type''file');  
  5.     input.setAttribute('accept''image/*');  
  6.     input.click();  
  7.   
  8.     input.onchange = async () => {  
  9.       var file: any = input.files[0];  
  10.       var formData = new FormData();  
  11.   
  12.       formData.append('image', file);  
  13.   
  14.       var fileName = file.name;  
  15.   
  16.       const res = await this.uploadFiles(file, fileName, quillObj);  
  17.     };  
  18.   }  
  • When the user clicks on the image icon of rich text control, it will call the above method. This method will create a control for file upload and call on the click method of file upload control.
  • So, on clicking the image icon of the rich text box, it will open the file selection popup and allow to select only the image file.
  • In imageHandler method, we also defined what should be done once the user selects the image from the file selection popup.
Step 7
 
Now, when the user selects the image, we need to upload the selected image in the particular SharePoint document library. So, create new document library if you want to upload an image in the specific document library, else you can also use the default available Shared Documents library.
 
Step 8
 
Here in the above code also you can see we are calling uploadFiles method. The code in the uploadfiles method will be as below,
  1. public async uploadFiles(uploadFileObj, filename, quillObj) {  
  2.     var libraryName = "ImageFiles";  
  3.     var context = this.props.context;  
  4.     var siteUrl = this.props.context.pageContext.site.absoluteUrl;  
  5.   
  6.     var currentdate = new Date();  
  7.     var fileNamePredecessor = currentdate.getDate().toString() + currentdate.getMonth().toString() + currentdate.getFullYear().toString() + currentdate.getTime().toString();  
  8.   
  9.     filename = fileNamePredecessor + filename;  
  10.   
  11.     //To Upload in root folder  
  12.     var apiUrl = `${siteUrl}/_api/Web/Lists/getByTitle('${libraryName}')/RootFolder/Files/Add(url='${filename}', overwrite=true)`;  
  13.     const digestCache: IDigestCache = this.props.context.serviceScope.consume(DigestCache.serviceKey);  
  14.     digestCache.fetchDigest(  
  15.       this.props.context.pageContext.web.serverRelativeUrl)  
  16.       .then(async (digest: string): Promise<void> => {  
  17.         try {  
  18.           if (uploadFileObj != '') {  
  19.             fetch(apiUrl, {  
  20.               method: 'POST',  
  21.               headers: {  
  22.                 'Content-Type''application/json;odata=verbose',  
  23.                 "X-RequestDigest": digest  
  24.               },  
  25.               body: uploadFileObj // This is your file object  
  26.             }).then((response) => {  
  27.               console.log(response);  
  28.               const range = quillObj.getEditorSelection();  
  29.   
  30.               var res = siteUrl + "/" + listName + "/" + filename;  
  31.   
  32.               quillObj.getEditor().insertEmbed(range.index, 'image', res);  
  33.             }).catch((error) =>  
  34.               console.log(error)  
  35.             );  
  36.           }  
  37.         }  
  38.         catch (error) {  
  39.           console.log('uploadFiles : ' + error);  
  40.         }  
  41.   
  42.       })  
  43.   }  
In the above code, the document library name is ImageFiles. Once the file is uploaded successfully, we will return the URL of the uploaded image to a rich text editor and will render the image in rich text control using the below line of code 
  1. quillObj.getEditor().insertEmbed(range.index, 'image', res);  
  • The image will be rendered at the particular place where the cursor’s position using quillObj which we have defined as a global variable and then used while rendering control.
  • Now when the user selects the image, it will first be uploaded to the SharePoint document library and then use the uploaded files URL to load the image in the rich text box.
  • When you inspect the image in rich text control, you can see the URL of the image, not the base 64 string of the image.
 
  • While saving into the list, when you get the value of rich text control, it will return the image control with the URL of the image. So in the list also it will store the URL of an image.

Conclusion


This is how we can use image upload functionality in the react quill rich text editor in the SPFx custom web part.
 
Hope this article will be helpful!