Downloading file from user uploads (dynamically handling) using Angular JS, Sp
In my recent project, I encountered a complex issue while implementing a file download feature for a document management system. The file download process required integration between an AngularJS frontend and a Java Spring Boot backend, with files stored dynamically on the server.
Outcome, when a link/button is clicked, it able to auto download inside local pc & able to successfully open the downloaded file:
Challenges:
When attempting to download files, I encountered various issues:
1. File Not Downloading Properly: Initial attempts to download files led to corrupted or unopenable files.
2. Dynamic Path Handling: The backend stored files in a specific directory, requiring a way to build the correct URL dynamically from AngularJS.
3. Browser Compatibility & Blob Usage: Some methods for file downloading worked inconsistently across browsers or introduced compatibility issues.
4. Need to follow a standardized Angular JS' $resource for making the backend calls to fetch files while dynamically building the download URL.
Solution:
1. Dynamic File Path Resolution in Java: I configured the Java backend to handle file paths using
Path filePath = Paths.get("path/directory").resolve(filename).normalize();
This allowed the backend to access files from a specified directory dynamically based on user input.
2. AngularJS Fetching with $resource
: Instead of using direct $http
requests, I utilized $resource
for consistency with other service calls, allowing smoother data fetching and handling response data more flexibly.
> What I mean by this is, this project has standardized to call the fetch API method using a service called FormService when it utilizes the Angular's $resource:
angular.module('app').factory('FormService', ['$resource', function($resource, $routeParams) {
//http://localhost:9090/api/../../..
var uparams = {modulecode: '@modulecode',caseid: '@caseid', version: '@version', p:'@p', action: '@action', id: '@id', mode: '@mode', process: '@process', taskid: '@taskid', filename: '@filename', filter: '@filter', type: '@type', module: '@module'}
return $resource(':url', uparams, {
downloadLetterFile : {method: 'GET',url: '/apps/api/docs/:filename',responseType: 'arraybuffer'},
This function is then called inside the Angular controller as I have describe in step part no.3 below.
3. Frontend Download Handling: I set up a fetch
API fallback, along with AngularJS $resource
functions, to handle the file download with checks for response validity and cross-browser compatibility.
> It involves with an HTML <a> element to trigger the download, allowing me to handle the download dynamically and with minimal compatibility issues. Here's the example of how I've implemented this:
$scope.downloadFile = function(letterfilename) {
if (!letterfilename) {
ciWarn("", "No filename provided for download.");
return;
}
// Define the download URL based on backend path and filename
const downloadUrl = $scope.baseUrl + '/api/docs/' + encodeURIComponent(letterfilename);
// Call FormService to fetch the file using $resource
FormService.downloadLetterFile({ filename: letterfilename }, function(response) {
if (response) {
// Create a temporary <a> element to trigger the download
const link = document.createElement('a');
link.href = downloadUrl; // Set the URL for the file
link.download = letterfilename; // Set the download attribute for filename
document.body.appendChild(link); // Append to DOM temporarily
link.click(); // Trigger download
document.body.removeChild(link); // Clean up by removing the link
} else {
ciWarn("", "File not found on the server.");
}
}, function(error) {
console.error("Error downloading file:", error);
ciWarn("", "Unable to download file due to a network error.");
});
};
Comments
Post a Comment