Rendering Flat JSON Data in the EJ2 TypeScript File Manager Control

22 Jun 202424 minutes to read

The File Manager uses a flat data object as an array of JavaScript objects for rendering, eliminating the need to define ajaxSettings url. To load a folder data as an array of JavaScript objects, use the File Manager component’s fileSystemData property with a type of fileData interface. This means you no longer need to use a separate service provider, as you can integrate services like Google, Amazon, Azure, and others directly into your JavaScript code using the FileManager’s action events. For example, you can integrate Google Drive by following the Google Drive API Quickstart guide for JavaScript.

Event Information

Event Name Description    
beforeDelete This event is triggered before the deletion of a file or folder occurs. It can be utilized to prevent the deletion of specific files or folders. Any actions, such as displaying a spinner for deletion, can be implemented here.    
delete DeleteEventArgs path, itemData, cancel. This event is triggered after the file or folder is deleted successfully. The deleted file or folder details can be retrieved here. Additionally, custom elements’ visibility can be managed here based on the application’s use case.
beforeFolderCreate This event is triggered before a folder is created. It allows for the restriction of folder creation based on the application’s use case.    
folderCreate This event is triggered when a folder is successfully created. It provides an opportunity to retrieve details about the newly created folder.    
search This event is triggered when a search action occurs in the search bar of the File Manager component. It triggers each character entered in the input during the search process.    
beforeRename This event is triggered when a file or folder is about to be renamed. It allows for the restriction of the rename action for specific folders or files by utilizing the cancel option.    
rename This event is triggered when a file or folder is successfully renamed. It provides an opportunity to fetch details about the renamed file.    
beforeMove This event is triggered when a file or folder begins to move from its current path through a copy/cut and paste action.    
move This event is triggered when a file or folder is pasted into the destination path.    

Local data

The FileManager can be populated with local data that contains the array of fileData interface objects with parentId mapping.

To render the root-level folder, specify the parentId as null, or there is no need to specify the parentId in the array of fileData interface objects.

import { FileManager, Toolbar, NavigationPane, DetailsView, ContextMenu, Permission, FileData} from '@syncfusion/ej2-filemanager';

FileManager.Inject(Toolbar, NavigationPane, DetailsView, ContextMenu);

/**
 * File Manager flat data sample
 */

let resultData: FileData[] = [
    {
        dateCreated: new Date("2023-11-15T19:02:02.3419426+05:30"),
        dateModified: new Date("2024-01-08T18:16:38.4384894+05:30"),
        filterPath: "",
        hasChild: true,
        id: '0',
        isFile: false,
        name: "Files",
        parentId: null,
        size: 1779448,
        type: "folder"
    }, 
    {
        dateCreated: new Date("2023-11-15T19:02:02.3419426+05:30"),
        dateModified: new Date("2024-01-08T16:55:20.9464164+05:30"),
        filterPath: "\\",
        hasChild: false,
        id: '1',
        isFile: false,
        name: "Archives",
        parentId: '0',
        size: 680786,
        type: "folder"
    },
    {
        dateCreated: new Date("2023-11-15T19:02:02.3419426+05:30"),
        dateModified: new Date("2024-01-08T16:55:20.9464164+05:30"),
        filterPath: "\\",
        hasChild: false,
        id: "2",
        isFile: false,
        name: "Audio",
        parentId: "0",
        size: 20,
        type: "folder"
    },
    {
        dateCreated: new Date("2023-11-15T19:02:02.3419426+05:30"),
        dateModified: new Date("2024-01-08T16:55:20.9464164+05:30"),
        filterPath: "\\",
        hasChild: false,
        id: "3",
        isFile: false,
        name: "Video",
        parentId: "0",
        size: 6172,
        type: "folder"
    },
    {
        dateCreated: new Date("2023-11-15T19:02:02.3419426+05:30"),
        dateModified: new Date("2024-01-08T16:55:20.9464164+05:30"),
        filterPath: "\\Archives\\",
        hasChild: false,
        id: "4",
        isFile: true,
        name: "EJ2_File_Manager",
        parentId: "1",
        size: 12403,
        type: ".docx"
    },
    {
        dateCreated: new Date("2023-11-15T19:02:02.3419426+05:30"),
        dateModified: new Date("2024-01-08T16:55:20.9464164+05:30"),
        filterPath: "\\Archives\\",
        hasChild: false,
        id: "5",
        isFile: true,
        name: "EJ2_File_Manager",
        parentId: "1",
        size: 90099,
        type: ".pdf"
    },
    {
        dateCreated: new Date("2023-11-15T19:02:02.3419426+05:30"),
        dateModified: new Date("2024-01-08T16:55:20.9464164+05:30"),
        filterPath: "\\Archives\\",
        hasChild: false,
        id: "6",
        isFile: true,
        name: "File_Manager_PPT",
        parentId: "1",
        size: 578010,
        type: ".pptx"
    },
    {
        dateCreated: new Date("2023-11-15T19:02:02.3419426+05:30"),
        dateModified: new Date("2024-01-08T16:55:20.9464164+05:30"),
        filterPath: "\\Archives\\",
        hasChild: false,
        id: "7",
        isFile: true,
        name: "File_Manager",
        parentId: "1",
        size: 274,
        type: ".txt"
    },
    {
        dateCreated: new Date("2023-11-15T19:02:02.3419426+05:30"),
        dateModified: new Date("2024-01-08T16:55:20.9464164+05:30"),
        filterPath: "\\Audio\\",
        hasChild: false,
        id: "8",
        isFile: true,
        name: "Music",
        parentId: "2",
        size: 10,
        type: ".mp3"
    },
    {
        dateCreated: new Date("2023-11-15T19:02:02.3419426+05:30"),
        dateModified: new Date("2024-01-08T16:55:20.9464164+05:30"),
        filterPath: "\\Audio\\",
        hasChild: false,
        id: "9",
        isFile: true,
        name: "Sample_Music",
        parentId: "2",
        size: 10,
        type: ".mp3"
    },
    {
        dateCreated: new Date("2023-11-15T19:02:02.3419426+05:30"),
        dateModified: new Date("2024-01-08T16:55:20.9464164+05:30"),
        filterPath: "\\Video\\",
        hasChild: false,
        id: "10",
        isFile: true,
        name: "Demo_Video",
        parentId: "3",
        size: 10,
        type: ".mp4"
    },
    {
        dateCreated: new Date("2023-11-15T19:02:02.3419426+05:30"),
        dateModified: new Date("2024-01-08T16:55:20.9464164+05:30"),
        filterPath: "\\Video\\",
        hasChild: false,
        id: "11",
        isFile: true,
        name: "Sample_Video",
        parentId: "3",
        size: 10,
        type: ".mp4"
    }
];
let fileObject: FileManager = new FileManager({
    fileSystemData: [].slice.call(resultData) as { [key: string]: Object }[],
    toolbarSettings: { items: ['NewFolder', 'Cut', 'Copy', 'Paste', 'Delete', 'Rename', 'SortBy', 'Refresh', 'Selection', 'View', 'Details'], visible: true },
    contextMenuSettings: { file: ["Cut", "Copy", "Paste", "Delete", "Rename", "|", "Details"], folder: ["Open", "|", "Cut", "Copy", "Paste", "|", "Delete", "Rename", "|", "Details"], layout: ["SortBy", "View", "Refresh", "|", "Paste", "|", "NewFolder", "|", "Details", "|", "SelectAll"], visible: true }
});
fileObject.appendTo('#filemanager');
<!DOCTYPE html>
<html lang="en">

<head>
    <title>Essential JS 2 File Manager</title>
    <meta charset="utf-8" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <meta name="description" content="Essential JS 2 File Manager Component" />
    <meta name="author" content="Syncfusion" />
    <link href="index.css" rel="stylesheet" />
    <link href="https://cdn.syncfusion.com/ej2/28.1.33/ej2-base/styles/material.css" rel="stylesheet" />
    <link href="https://cdn.syncfusion.com/ej2/28.1.33/ej2-inputs/styles/material.css" rel="stylesheet" />
    <link href="https://cdn.syncfusion.com/ej2/28.1.33/ej2-popups/styles/material.css" rel="stylesheet" />
    <link href="https://cdn.syncfusion.com/ej2/28.1.33/ej2-buttons/styles/material.css" rel="stylesheet" />
    <link href="https://cdn.syncfusion.com/ej2/28.1.33/ej2-splitbuttons/styles/material.css" rel="stylesheet" />
    <link href="https://cdn.syncfusion.com/ej2/28.1.33/ej2-layouts/styles/material.css" rel="stylesheet" />
    <link href="https://cdn.syncfusion.com/ej2/28.1.33/ej2-navigations/styles/material.css" rel="stylesheet" />
    <link href="https://cdn.syncfusion.com/ej2/28.1.33/ej2-grids/styles/material.css" rel="stylesheet" />
    <link href="https://cdn.syncfusion.com/ej2/28.1.33/ej2-filemanager/styles/material.css" rel="stylesheet" />
    <script src="https://cdnjs.cloudflare.com/ajax/libs/systemjs/0.19.38/system.js"></script>
    <script src="systemjs.config.js"></script>
<script src="https://cdn.syncfusion.com/ej2/syncfusion-helper.js" type ="text/javascript"></script>
</head>
<body>
    <div id='loader'>Loading....</div>
    <div id="container">
        <div id="filemanager"></div>
    </div>
</body>
</html>

Rendering Flat JSON Data from Google service

In the following topic, we can learn about reading files from Google API using the File Manager’s action events. This eliminates the need to define ajaxSettings url.

These events enable you to access essential item details from the event argument. To perform file operation corresponding to your service, use the cancel property in File Manager’s action event and customize the fileSystemData based on your current service data.

The example retrieves the google drive file details as Flat data object and handle the read response from source by updating fileSystemData property with retrieved data.

To set up File Manager component with google service, create a client ID and API key for your google account. To learn more about generating the client credentials from the from Google API Console, refer to this link.

async function fetchData() {
    // Load the Drive API client library
    await gapi.client.load('drive', 'v3');
    let nextPageToken = null;
    let allFiles = [];
    do {
        const response = await gapi.client.drive.files.list({
        pageSize: 1000,
        fields: 'nextPageToken, files(id, name, mimeType, size, parents, thumbnailLink, trashed)',
        pageToken: nextPageToken,
        q: 'trashed=false'
        });
        allFiles = allFiles.concat(response.result.files);
        nextPageToken = response.result.nextPageToken;
    } while (nextPageToken);
    const files = allFiles;
    // Create a flat array representing parent-child relationships for File Manager fileSystemData property
    window.fileSystemData = await createFlatData(files);
}

async function createFlatData(files) {
...
  await Promise.all(files.map(async file => {
      isFileOrFolder = file.mimeType == 'application/vnd.google-apps.folder' ? false : true;
      if (!isFileOrFolder) {
      hasSubitems = file.name == 'Files'? true : doesFolderHaveSubfolders(fileList, file.id);
      }
      var fileType = getFileTypeFromName(file.name);
      var imageUrl = file.thumbnailLink;
      //Frame File Manager response data by retrieveing the folder details from google service.
      if (file.name == 'Files') {
      rootId = file.id;
      fileDetails = {
          id: '0',
          name: file.name,
          parentId: null,
          isFile: file.mimeType == 'application/vnd.google-apps.folder'? false : true,
          hasChild: hasSubitems,
          size: file.size == undefined? '0' : file.size,
          filterPath: '',
          originalID: file.id
      };
      } else {
      fileDetails = {
          id: file.id,
          name: file.name,
          isFile: file.mimeType == 'application/vnd.google-apps.folder' ? false : true,
          hasChild: hasSubitems,
          size: file.size == undefined? '0' : file.size,
          filterPath: file.filterPath,
          imageUrl: imageUrl,
          originalID: file.id
      };
      }
      if (file.parents) {
      file.parents.forEach(async parentId => {
          parentDetails = {
          id: fileDetails.id,
          name: fileDetails.name,
          parentId: fileDetails.name == "Files" ? null : parentId,
          isFile: fileDetails.isFile,
          type: fileDetails.isFile ? fileType : "",
          hasChild: fileDetails.hasChild,
          size: fileDetails.size,
          filterPath: fileDetails.name == "Files" ? "" : fileDetails.filterPath,
          imageUrl: fileDetails.imageUrl,
          originalID: fileDetails.originalID
          };
          await flatData.push(parentDetails);
          flatData.sort((a, b) => a.name.localeCompare(b.name));
      });
      } else {
      // If a file has no parents, it is a root-level item
      await flatData.push(fileDetails);
      }
  }));

    ...
  // Return flat array representing parent-child relationships from Google Drive
  return await(newData);
  }

Delete action

To enable the delete operation in the File Manager component with Google services, you can use the beforeDelete event. By setting the cancel property to true in the beforeDelete event, you can prevent the default delete action of the File Manager component. Then, you can make a Google API request with the help of event argument to delete the file from Google Drive. Additionally, to update the fileSystemData property with the current Google Drive data, you can call the fetchData method in the gapi success callback. This ensures that the File Manager component remains synchronized with the Google Drive data during the delete operation.

Here is an example of how you can handle the delete operation using the beforeDelete event:

  beforeDelete: function deleting(args) {
      // Cancel the default delete action
      args.cancel = true;
      // Create a new Drive API request to delete the file or folder
      args.itemData.forEach(function(item) {
        gapi.client.drive.files.delete({
          fileId: item.originalID,
        }).then(function(response) {
          // Success: load the updated Google Drive data within File Manager component.
          fetchData();
        }, function(error) {
          console.error('Error deleting folder:', error);
        });
      });
  },

Copy action

To enable the copy operation in the File Manager component with Google services, you can use the beforeMove event. The isCopy property in the event argument in true for copy operation. By setting the cancel property to true in the beforeMove event, you can prevent the default copy action of the File Manager component. Then, you can make a Google API request with the help of event argument to copy the file from Google Drive. Additionally, to update the fileSystemData property with the current Google Drive data, you can call the fetchData method in the gapi success callback. This ensures that the File Manager component remains synchronized with the Google Drive data during the copy operation.

Here is an example of how you can handle the copy operation using the beforeMove event:

  beforeMove: function moving(args) {
    // Cancel the default move action
    args.cancel = true;
    // Check if the operation is a copy or a cut
    if(args.isCopy) {
      // Update the parents property to move the file to the new folder
      var newParentFolderId = args.targetData.originalID;
      // Perform copy operation.
      args.itemData.forEach(async function(item) {
        var originalFolderId = item.originalID;
        // Check if the item is a folder or a file
        if(item.type == "") {
          // Get information about the original folder
          gapi.client.drive.files.get({
              fileId: originalFolderId,
              fields: 'id,name,parents,kind,mimeType'
          }).then(function(response) {
              var folderMetadata = response.result;
              // Create a new folder in the destination
              gapi.client.drive.files.create({
                  resource: {
                      name: folderMetadata.name,
                      mimeType: folderMetadata.mimeType,
                      parents: [newParentFolderId]
                  }
              }).then(function(newFolder) {
                  // Get the contents of the original folder
                  gapi.client.drive.files.list({
                      q: "'" + originalFolderId + "' in parents",
                      fields: 'files(id,name,kind,mimeType)',
                      pageSize: 1000
                  }).then(function(contentsResponse) {
                      var contents = contentsResponse.result.files;
                      // Iterate through the contents and copy each file or subfolder
                      contents.forEach(function(item) {
                          if (item.kind === 'drive#folder') {
                              // Recursively copy subfolders
                              copyFolder(item.id, newFolder.result.id);
                          } else {
                              // Copy files
                              gapi.client.drive.files.copy({
                                  fileId: item.id,
                                  resource: {
                                      name: item.name,
                                      parents: [newFolder.result.id]
                                  }
                              }).then(function(copiedFile) {
                                  // Update the copied file's properties if needed
                                  var updatedProperties = {
                                      // Add any additional properties you want to update
                                  };

                                  gapi.client.drive.files.update({
                                      fileId: copiedFile.result.id,
                                      resource: updatedProperties
                                  }).then(function(updatedFile) {
                                    // Success: load the copied Google Drive folder data within File Manager component.
                                    fetchData();
                                  ...
      return;
    }
  ...
  // Function to copy a folder and its contents
  async function copyFolder(originalFolderId, newParentFolderId) {
    // Get information about the original folder
    await gapi.client.drive.files.get({
        fileId: originalFolderId,
        fields: 'id,name,parents,kind,mimeType'
    }).then(async function(response) {
        var folderMetadata = response.result;
        // Create a new folder in the destination
        await gapi.client.drive.files.create({
            resource: {
                name: folderMetadata.name,
                mimeType: folderMetadata.mimeType,
                parents: [newParentFolderId]
            }
        }).then(async function(newFolder) {
            // Get the contents of the original folder
            await gapi.client.drive.files.list({
                q: "'" + originalFolderId + "' in parents",
                fields: 'files(id,name,kind,mimeType)',
                pageSize: 1000
            }).then(async function(contentsResponse) {
                var contents = contentsResponse.result.files;

                // Iterate through the contents and copy each file or subfolder
                contents.forEach(async function(item) {
                    if (item.kind === 'drive#folder') {
                        // Recursively copy subfolders
                        copyFolder(item.id, newFolder.result.id);
                    } else {
                        // Copy files
                        await gapi.client.drive.files.copy({
                            fileId: item.id,
                            resource: {
                                name: item.name,
                                parents: [newFolder.result.id]
                            }
                        }).then(async function(copiedFile) {
                            // Update the copied file's properties if needed
                            var updatedProperties = {
                                // Add any additional properties you want to update
                            };

                            await gapi.client.drive.files.update({
                                fileId: copiedFile.result.id,
                                resource: updatedProperties
                            }).then(function(updatedFile) {
                            }).catch(function(error) {
                                console.error('Error updating copied file:', error);
                            });
                        }).catch(function(error) {
                            console.error('Error copying file:', error);
                        });
                    }
                });
              ...

Move action

To enable the move operation in the File Manager component with Google services, you can use the beforeMove event. The isCopy property in the event argument in false for move operation. By setting the cancel property to true in the beforeMove event, you can prevent the default move action of the File Manager component. Then, you can make a Google API request with the help of event argument to move the file from Google Drive. Additionally, to update the fileSystemData property with the current Google Drive data, you can call the fetchData method in the gapi success callback. This ensures that the File Manager component remains synchronized with the Google Drive data during the move operation.

Here is an example of how you can handle the move operation using the beforeMove event:

  beforeMove: function moving(args) {
    // Cancel the default move action
    args.cancel = true;
    ...
    //Perform cut operation.
    args.itemData.forEach(function(item) {
      // Get information about the original file
      gapi.client.drive.files.get({
          fileId: item.originalID,
          fields: 'id,parents', // Add any other fields you might need
      }).then(function(response) {
        var fileMetadata = response.result;
        // Update the parents property to move the file to the new folder
        var newParentFolderId = [args.targetData.originalID];
        // Send the update request
        gapi.client.drive.files.update({
            fileId: item.originalID,
            addParents: newParentFolderId,
            removeParents: fileMetadata.parents[0],
        }).then(function(updatedFile) {
            // Success: load the Google Drive moved file data within File Manager component.
            fetchData();
        }, function(error) {
            console.error('Error moving file:', error);
        });
      }, function(error) {
          console.error('Error retrieving file metadata:', error);
      });
    });
  },

Folder create action

To enable the folder create operation in the File Manager component with Google services, you can use the beforeFolderCreate event. By setting the cancel property to true in the beforeFolderCreate event, you can prevent the default folder create action of the File Manager component. Then, you can make a Google API request with the help of event argument to create folder to Google Drive. Additionally, to update the fileSystemData property with the current Google Drive data, you can call the fetchData method in the gapi success callback. This ensures that the File Manager component remains synchronized with the Google Drive data during the folder creation operation.

Here is an example of how you can handle the folder creation operation using the beforeFolderCreate event:

  beforeFolderCreate: function onCreate(args) {
    // Cancel the default folder creation action
    args.cancel = true;
    // Create a new Drive API request to create a folder
    var body = {
      'name': args.folderName,
      'mimeType': "application/vnd.google-apps.folder",
      'parents': [args.parentFolder[0].originalID]
    };
    var request = gapi.client.drive.files.create({
      'resource': body
    });
    request.execute(function(resp) {
      if (resp.error) {
        console.error('Error:', resp.error.message);
      } else {
        // success: load the newly created Google Drive data within File Manager component.
        fetchData();
      }
    });
},

Rename action

To enable the rename operation in the File Manager component with Google services, you can use the beforeRename event. By setting the cancel property to true in the beforeRename event, you can prevent the default rename action of the File Manager component. Then, you can make a Google API request with the help of event argument to rename the file from Google Drive. Additionally, to update the fileSystemData property with the current Google Drive data, you can call the fetchData method in the gapi success callback. This ensures that the File Manager component remains synchronized with the Google Drive data during the rename operation.

Here is an example of how you can handle the rename operation using the beforeRename event:

  beforeRename: function rename(args) {
    // Cancel the default rename action
    args.cancel = true;
    // Create a new Drive API request to find the file or folder name
    gapi.client.drive.files.list({
      q: "name = '" + args.itemData[0].name + "'",
      fields: 'files(id,name,parents)', // Add any other fields you might need
    }).then(function(response) {
      var files = response.result.files;

      if (files && files.length > 0) {
        // The first file in the list is the one you're looking for
        var foundFile = files[0];
        var metadata = {
          name: args.newName,
        };
        // Create a new Drive API request to rename the file or folder name
        gapi.client.drive.files.update({
          fileId: foundFile.id,
          resource: metadata,
        }).then(function(updatedFile) {
          // Success: load the renamed Google Drive data within File Manager component.
          fetchData();
        }, function(error) {
          console.error('Error updating file:', error);
        });
      }
    }, function(error) {
      console.error('Error retrieving file metadata:', error);
    });
},

Upload action

To enable the upload operation in the File Manager component with Google services, you can use the uploadListCreate event. This event provides access to details of the file selected in the browser, including metadata such as the file name, size, and content type. Using the event argument, you can make a Google API request to upload the file to Google Drive. Additionally, to update the fileSystemData property with the current Google Drive data, you can call the fetchData method in the gapi success callback. This ensures that the File Manager component remains synchronized with the Google Drive data during the upload operation.

Here is an example of how you can handle the upload operation using the uploadListCreate event:

  uploadListCreate: async function uploadFile(args) {
    var fileObj = document.getElementById("file").ej2_instances[0];
    var pathArray = fileObj.pathNames;
    var folderName = pathArray[pathArray.length -1 ];
    var parentFolderId = fileObj.fileSystemData.filter(function(obj) { return obj.name == folderName; })[0].originalID;
    var folders = args.fileInfo.name.split('/');
    var fileName = folders.length > 1 ? folders[folders.length - 1] : args.fileInfo.name;
    const file = args.fileInfo.rawFile;
    // Create a new Drive API request to upload a file
    var body = {
      'name': fileName,
      'mimeType': args.fileInfo.type,
      'parents': [parentFolderId]
    };
    var request = gapi.client.drive.files.create({
      'resource': body
    });
    request.execute(function(resp) {
      if (resp.error) {
        console.error('Error:', resp.error.message);
        args.element.getElementsByClassName("e-file-status")[0].innerText = "Upload Failed";
        args.element.getElementsByClassName("e-file-status")[0].classList.add("e-upload-fails");
      } else {
        // Success: load the uploaded data within File Manager component.
        args.element.getElementsByClassName("e-file-status")[0].innerText = "Upload successful";
        args.element.getElementsByClassName("e-file-status")[0].classList.add("e-upload-success");
        // Success: load the updated Google Drive data within File Manager component.
        fetchData();
      }
    });
  },

Download action

To enable the Download operatipon in the File Manager component with Google services, you can use the beforeDownload event. This event provides access to details of the file selected in the File Manager. By setting the cancel property to true in the beforeDownload event, you can prevent the default delete action of the File Manager component. Then, you can make a Google API request with the help of event argument to Download the raw file from Google Drive.

  beforeDownload: function beforeDownload(args) {
    // Cancel the default download action
    args.cancel = true;
    var fileData = args.data.data;
    const zip = new JSZip();
    //To download multiple files as zip folder.
    if(fileData.length > 1 || !fileData[0].isFile) {
      downloadFiles(fileData);
    }
    //To download single file.
    else {
      // Fetch the file content using the Google Drive API
      fetch(`https://www.googleapis.com/drive/v3/files/${fileData[0].id}?alt=media`, {
          method: 'GET',
          headers: {
              'Authorization': 'Bearer ' + gapi.auth.getToken().access_token,
          },
      })
      .then(function(response) {
          if (!response.ok) {
              throw new Error('Network response was not ok: ' + response.statusText);
          }
          return response.blob();
      })
      .then(function(blob) {
          // Display image preview
          var img = document.createElement('img');
          img.src = URL.createObjectURL(blob);
          img.alt = fileData[0].name; // Set alternative text
          document.body.appendChild(img);

          // Create a download link
          var downloadLink = document.createElement('a');
          downloadLink.href = URL.createObjectURL(blob);
          downloadLink.download = fileData[0].name; // Set the desired file name
          document.body.appendChild(downloadLink);
          downloadLink.click();

          // Remove the link and image from the document
          document.body.removeChild(downloadLink);
          document.body.removeChild(img);
      })
      .catch(function(error) {
          console.error('Error downloading file:', error);
      });
    }
  },
  ...

  function downloadFiles(files) {
    const zip = new JSZip();
    const totalCount = files.some(file => file.type === "") ? getTotalFileCount(files) : files.length;
    const name = files.some(file => file.type == "") ? 'folders' : 'files';
    // Iterate through files and add them to the zip
    files.forEach(file => {
      if (file.type === '') {
        // If it's a folder, recursively fetch its contents
        fetchFolderContents(file.id).then(response => {
          downloadFiles(response.result.files);
        });
      } else {
        // If it's a file, download and add it to the zip
        fetch(`https://www.googleapis.com/drive/v3/files/${file.id}?alt=media`, {
          method: 'GET',
          headers: {
            'Authorization': 'Bearer ' + gapi.auth.getToken().access_token,
          },
        })
        .then(response => {
          if (!response.ok) {
            throw new Error('Network response was not ok: ' + response.statusText);
          }
          return response.blob();
        })
        .then(blob => {
          // Add file content to the zip
          zip.file(file.name, blob);

          // Check if all files are added, then create the zip
          if (Object.keys(zip.files).length === totalCount) {
            zip.generateAsync({ type: 'blob' }).then(zipBlob => {
              // Trigger download
              const a = document.createElement('a');
              a.href = URL.createObjectURL(zipBlob);
              a.download = name + '.zip';
              document.body.appendChild(a);
              a.click();
              document.body.removeChild(a);
            });
          }
        })
        .catch(error => {
          console.error('Error downloading file:', error);
        });
      }
    });
  }

Get image action

To enable the image preview in the File Manager component with Google services, you can use the File Manager fileSystemData property response with imageUrl field.

In the example, the File Manager retrieves the Google Drive file details as flat data and update the imageUrl field with Google Drive’s file thumbnailLink at initial render.

  async function createFlatData(files) {
  ...
    await Promise.all(files.map(async file => {
      ...
      var imageUrl = file.thumbnailLink;
      //Frame File Manager response data by retrieveing the folder details from google service.
      if (file.name == 'Files') {
        rootId = file.id;
        fileDetails = {
          id: '0',
          name: file.name,
          parentId: null,
          isFile: file.mimeType == 'application/vnd.google-apps.folder'? false : true,
          hasChild: hasSubitems,
          size: file.size == undefined? '0' : file.size,
          filterPath: '',
          originalID: file.id
        };
      } else {
        fileDetails = {
          id: file.id,
          name: file.name,
          isFile: file.mimeType == 'application/vnd.google-apps.folder' ? false : true,
          hasChild: hasSubitems,
          size: file.size == undefined? '0' : file.size,
          filterPath: file.filterPath,
          imageUrl: imageUrl,
          originalID: file.id
        };
      }
      ...

Note: For a complete example on handling Google Drive file details as flat data in the File Manager component, view the example on GitHub.