ng-file-upload How to use Upload.rename(file, newName) - multer

I am using ng-file-upload and multer to store files in an uploads folder and I also save the filename to database but of course not at the same instant. So if I want to save the original filename, multer will do this like:
filename: function (req, file, cb) {
cb(null, file.originalname);
I can use
cb(null, file.originalname + '-' + Date.now());
to make the name unique but then the filename in the database (taken from the ng-file-upload service) is different.
I want to use Upload.rename(file, newName) as on the github/danialfarid/ng-file-upload page but all my attempts to use it have failed.
This is the ng-file-upload code (first part)
$scope.uploadPic = function(files) {
for(var i = 0; i < $scope.files.length; i++) {
var $file = $scope.files[i];
(function(index) {
$scope.upload[index] = Upload.upload({
url: '/',
method: 'POST',
file: $file,
}).progress(function (evt) {
$scope.files[index].progress = Math.min(100, parseInt(100.0 * evt.loaded / evt.total));
}).then(function (response) {
$timeout(function () {
$file.result = response.data;
I have tried var newName = $file.name + '-' + Date.now()
but then I am unsure of how to apply Upload.rename(file, newName)
I thought if I set the new name before multer gets hold of it then the uploads folder and the database will have the same name.
At least that's the idea. Can anyone help?

in the upload options, set the file key as the name of the file and use the same key for the multer options e.g:
if you have this for your ng-file-upload options:
$scope.upload[index] = Upload.upload({
url: '/',
method: 'POST',
nameOfImage: $file,
})
for multer, you should also have
upload.single('nameOfImage')
I tried this using multer v1.2.0 and ng-file-upload 12.2.12

I was using an older version of ng-file-upload (7.X.X) which didn't have this in ng-file-upload.js
this.rename = function (file, name) {
file.ngfName = name;
return file;
};
I updated to version 10.0.2
So now I can use Upload.rename($file, 'preview1.jpg');
and the file is saved with the new name.

Related

how to display a file using react-native

So, I have those "cards" to which are attached files.
I want to be able to display the content of these files (when possible; I do not expect to show binary files obviously, but text, pdf, images,...) to the user.
Upon a longPress on an attachment, the openAttachment() function is be called. That function downloads the file from the server if necessary and then (tries to) open it:
// Opens an attachment
const openAttachment = async (attachment) => {
try {
// Download file if not already done
const fileInfo = await FileSystem.getInfoAsync(FileSystem.cacheDirectory + attachment.name)
let uri
if (!fileInfo.exists) {
console.log('Downloading attachment')
resp = await FileSystem.downloadAsync(
server.value + `/index.php/apps/deck/api/v1.0/boards/${route.params.boardId}/stacks/${route.params.stackId}/cards/${route.params.cardId}/attachments/${attachment.id}`,
FileSystem.cacheDirectory + attachment.name,
{
headers: {
'Authorization': token.value
},
},
)
console.log(resp)
uri = await FileSystem.getContentUriAsync(resp.uri)
} else {
console.log('File already in cache')
uri = await FileSystem.getContentUriAsync(fileInfo.uri)
}
console.log('Opening file ' + uri)
Sharing.shareAsync(uri);
} catch {
Toast.show({
type: 'error',
text1: i18n.t('error'),
text2: error.message,
})
console.log(error)
}
}
The issue always arrise at the Sharing.shareAsync(uri); line: Whatever I put there, it fails:
Sharing.shareAsync(uri) does not seem to be supported on my platform: https://docs.expo.dev/versions/latest/sdk/sharing/
Linking.openURL(uri) does not support the file:// scheme (the uri is in the form file:///var/mobile/Containers/Data/Application/5C1CB402-5ED1-4E17-B907-46111AE3FB7C/Library/Caches/test.pdf)
await WebBrowser.openBrowserAsync(uri) (from expo-web-browser) does not seem to be able to open local files
How am I supposed to do to display those files? Anyone has an idea?
Cyrille
I found a solution using react-native-file-viewer
// Opens an attachment
const openAttachment = async (attachment) => {
try {
// Download file if not already done
const fileInfo = await FileSystem.getInfoAsync(FileSystem.cacheDirectory + "attachment.name")
let uri
if (!fileInfo.exists) {
console.log('Downloading attachment')
const resp = await FileSystem.downloadAsync(
server.value + `/index.php/apps/deck/api/v1.0/boards/${route.params.boardId}/stacks/${route.params.stackId}/cards/${route.params.cardId}/attachments/${attachment.id}`,
FileSystem.cacheDirectory + attachment.name,
{
headers: {
'Authorization': token.value
},
},
)
console.log(resp)
uri = await FileSystem.getContentUriAsync(resp.uri)
} else {
console.log('File already in cache')
uri = await FileSystem.getContentUriAsync(fileInfo.uri)
}
console.log('opening file', uri)
FileViewer.open(uri)
} catch(error) {
Toast.show({
type: 'error',
text1: i18n.t('error'),
text2: error.message,
})
console.log(error)
}
}

Save binary data with Electron

in my Electron app I need to upload a file (.mp3) using a normal html input and then save it on the disk.
I'm reading the file using the browser's FileReader:
const reader = new FileReader();
reader.onload = () => {
resolver.next(reader.result as string);
resolver.complete();
};
reader.readAsBinaryString(file);
Then I sent the readed content like this:
this.electronService.ipcRenderer.on('aaaSuccess', (_, newPath) =>
this.store$.dispatch(HomeActions.changeSuccess({ soundName: action.sound.name, newPath })));
this.electronService.ipcRenderer.send('aaa', { fileName: file.name, content: base64 });
Then I pass the readed binary string to the mainProcess like this:
ipcMain.on('aaa', (event, { fileName, content }) => {
var newPath = path.join(app.getPath('userData'), fileName);
fs.writeFile(newPath, content, function (err) {
if (err) { return console.log('error is writing new file', err) }
event.reply('aaaSuccess', newPath)
});
})
This code works, but the dimension in bytes of the saved file is different from the original one, and it can't be opened using an mp3 player
Thanks a lot

How to upload file in angular 2

This is the function I am using to upload file but is is giving me the error : Length is undefined. what I have to change in this code. where to give path of file to upload.
fileChange(event) {
let fileList: FileList = event.target.files;
if(fileList) {
let file: File = fileList[0];
let formData:FormData = new FormData();
formData.append('uploadFile', file, file.name);
let headers = new Headers();
/** No need to include Content-Type in Angular 4 */
headers.append('Content-Type', 'multipart/form-data');
headers.append('Accept', 'application/json');
let options = new RequestOptions({ headers: headers });
this.http.post(`assets/Files/info.txt`, formData, options)
.map(res => res.json())
.catch(error => Observable.throw(error))
.subscribe(
data => console.log(fileList),
error => console.log(error)
)
}
}
you need to use xhr request to transfer files
fileChange(event: EventTarget) {
let eventObj: MSInputMethodContext = <MSInputMethodContext> event;
let target: HTMLInputElement = <HTMLInputElement> eventObj.target;
let files: FileList = target.files;
if(files) {
let file: File = files[0];
this.upload(file)
}
}
public upload(filedata: File) {
let url = 'your url'
if (typeof filedata != 'undefined') {
return new Promise((resolve, reject) => {
let formData: any = new FormData();
let xhr = new XMLHttpRequest();
formData.append('icondata', filedata, filedata.name);
xhr.open('POST', url, true);
xhr.setRequestHeader('Authorization', 'JWT ' + localStorage.getItem('id_token'));
xhr.send(formData);
xhr.onreadystatechange = function () {
if (xhr.readyState == XMLHttpRequest.DONE) {
resolve(JSON.parse(xhr.responseText));
}
}
});
}
}
I understand that this is not the functionality you want to have but with no backend you can not upload files to be persistent, they should be stored somewhere. If you just wanna manipulate file names for instance, skip the express part in my answer. I personally used this code which I altered to upload multiple files.
In your Component :
import {FormArray, FormBuilder, FormControl, FormGroup} from "#angular/forms";
declare FormBuilder in the constructor:
constructor (private http: Http, private fb: FormBuilder) {}
in ngOnInit() set a variable as follows :
this.myForm = this.fb.group({chosenfiles: this.fb.array([])});
this is the code for the upload method :
// invoke the upload to server method
// TODO
// Should be in a service (injectable)
upload() {
const formData: any = new FormData();
const files: Array<File> = this.filesToUpload;
//console.log(files);
const chosenf = <FormArray> this.myForm.controls["chosenfiles"];
// iterate over the number of files
for(let i =0; i < files.length; i++){
formData.append("uploads[]", files[i], files[i]['name']);
// store file name in an array
chosenf.push(new FormControl(files[i]['name']));
}
this.http.post('http://localhost:3003/api/upload', formData)
.map(files => files.json())
.subscribe(files => console.log('upload completed, files are : ', files));
}
the method responsible for the file change :
fileChangeEvent(fileInput: any) {
this.filesToUpload = <Array<File>>fileInput.target.files;
const formData: any = new FormData();
const files: Array<File> = this.filesToUpload;
console.log(files);
const chosenf = <FormArray> this.myForm.controls["chosenfiles"];
// iterate over the number of files
for(let i =0; i < files.length; i++){
formData.append("uploads[]", files[i], files[i]['name']);
// store file name in an array
chosenf.push(new FormControl(files[i]['name']));
}
}
Template is something like this
<input id="cin" name="cin" type="file" (change)="fileChangeEvent($event)" placeholder="Upload ..." multiple/>
Notice multiple responsible for allowing multiple selections
The express API which will handle the request uses multer after an npm install
var multer = require('multer');
var path = require('path');
specify a static directory which will hold the files
// specify the folder
app.use(express.static(path.join(__dirname, 'uploads')));
As specified by multer
PS: I did not investigate multer, as soon as i got it working, i moved to another task but feel free to remove unnecessary code.
var storage = multer.diskStorage({
// destination
destination: function (req, file, cb) {
cb(null, './uploads/')
},
filename: function (req, file, cb) {
cb(null, file.originalname);
}
});
var upload = multer({ storage: storage });
And finally the endpoint
app.post("/api/upload", upload.array("uploads[]", 12), function (req, res) {
console.log('files', req.files);
res.send(req.files);
});

How can i read a file from iCloud in an iOS-device with cordova?

I want to read the content of a PDF file stored in iCloud.
I pick the file with the FilePicker Phonegap iOS Plugin (https://github.com/jcesarmobile/FilePicker-Phonegap-iOS-Plugin).
The plugin gives me the temporary path where the file is copied.
I want to read it whith the Cordova File Plugin (https://github.com/apache/cordova-plugin-file)
but I did something wrong and the log is always giving me an error.
Here is the code:
$scope.successCallback = function (path) {
var fileName = path.substr(path.lastIndexOf('/') + 1);
var fileDir = path.substr(0,path.lastIndexOf('/') + 1)
console.log("FilePath: " + path);
$cordovaFile.readAsDataURL(fileDir, fileName)
.then(function (data) {
var index = data.indexOf("base64,");
if(index > 0)
{
data = data.substr(index+7);
}
console.log("Data OK=" + data);
}, function (error) {
console.log("Error reading file: " + JSON.stringify(error));
});
}
window.FilePicker.pickFile($scope.successCallback, $scope.errorCallback);
And that's the output:
$FilePath: /private/var/mobile/Containers/Data/Application/22E33EF4-832B-4911-92A6-312927C42A7C/tmp/DocumentPickerIncoming/file.pdf
$Error reading file: {"code":5,"message":"ENCODING_ERR"}
What am I doing wrong?
I realized that in the File Path was a "tmp" folder.
According of this, I changed the "fileDir" in order to matching the cordova.file properties map to physical paths on a real device which is referred in the iOS File System Layout of the documentation of cordova-plugin-file.
Now it works :)
Here is the final code:
$scope.successCallback = function (path) {
var fileName = path.substr(path.lastIndexOf('/') + 1);
var fileDir = cordova.file.tempDirectory + "DocumentPickerIncoming/";
console.log("FilePath: " + path);
$cordovaFile.readAsDataURL(fileDir, fileName)
.then(function (data) {
var index = data.indexOf("base64,");
if(index > 0)
{
data = data.substr(index+7);
}
console.log("Data OK=" + data);
}, function (error) {
console.log("Error reading file: " + JSON.stringify(error));
});
}
window.FilePicker.pickFile($scope.successCallback, $scope.errorCallback);

Cordova / Ionic - Download file from InAppBrowser

The scenario goes like this: I open a website in InAppBrowser, after the user ends with the work over there, the site generates a .pdf for the user to download, the problem is that the pdf does not download, it opens it in the browser.
Is there a way to make it download from the InAppBrowser? I'm currently working on an iOS app, so the solution would be better for iOS.
Thanks in advance.
Following #jcesarmobile advices this is what I came up with:
First I had to install the cordova-plugin-file-transfer
Open URL
var url = "http://mi-fancy-url.com";
var windowref = window.open(url, '_blank', 'location=no,closebuttoncaption=Cerrar,toolbar=yes,enableViewportScale=yes');
Create a listener on that windowref for a loadstart event and check if what's being loaded is a pdf (that's my case).
windowref.addEventListener('loadstart', function(e) {
var url = e.url;
var extension = url.substr(url.length - 4);
if (extension == '.pdf') {
var targetPath = cordova.file.documentsDirectory + "receipt.pdf";
var options = {};
var args = {
url: url,
targetPath: targetPath,
options: options
};
windowref.close(); // close window or you get exception
document.addEventListener('deviceready', function () {
setTimeout(function() {
downloadReceipt(args); // call the function which will download the file 1s after the window is closed, just in case..
}, 1000);
});
}
});
Create the function that will handle the file download and then open it:
function downloadReceipt(args) {
var fileTransfer = new FileTransfer();
var uri = encodeURI(args.url);
fileTransfer.download(
uri, // file's uri
args.targetPath, // where will be saved
function(entry) {
console.log("download complete: " + entry.toURL());
window.open(entry.toURL(), '_blank', 'location=no,closebuttoncaption=Cerrar,toolbar=yes,enableViewportScale=yes');
},
function(error) {
console.log("download error source " + error.source);
console.log("download error target " + error.target);
console.log("upload error code" + error.code);
},
true,
args.options
);
}
The problem i'm facing now is the path where it downloads, I just can't open it. But well, at least file is now downloaded. I will have to create a localStorage item to save the paths for different files.
Many validations are missing in this steps, this was just an example I made quickly to check if it works. Further validations are needed.
Open you window using IAB plugin and add an event listener
ref = window.open(url, "_blank");
ref.addEventListener('loadstop', loadStopCallBack);
In the InAppBrowser window call the action using https://xxx.pdf">documentName
Implement the loadStopCallBack function
function loadStopCallBack(refTemp) {
if(refTemp.url.includes('downloadDoc')) {
rtaParam = getURLParams('downloadDoc', refTemp.url);
if(rtaParam != null)
downloadFileFromServer(rtaParam);
return;
}
}
function getURLParams( name, url ) {
try {
if (!url)
url = location.href;
name = name.replace(/[\[]/, "\\\[").replace(/[\]]/, "\\\]");
var regexS = "[\\?&]" + name + "=([^&#]*)";
var regex = new RegExp(regexS);
var results = regex.exec(url);
return results == null ? null : results[1];
} catch (e) {
showSMS(e);
return null;
}
}
After create a download method
function downloadFileFromServer(fileServerURL){
try {
var Downloader = window.plugins.Downloader;
var fileName = fileServerURL.substring(fileServerURL.lastIndexOf("/") + 1);
var downloadSuccessCallback = function(result) {
console.log(result.path);
};
var downloadErrorCallback = function(error) {
// error: string
console.log(error);
};
//TODO cordova.file.documentsDirectory for iOS
var options = {
title: 'Descarga de '+ fileName, // Download Notification Title
url: fileServerURL, // File Url
path: fileName, // The File Name with extension
description: 'La descarga del archivo esta lista', // Download description Notification String
visible: true, // This download is visible and shows in the notifications while in progress and after completion.
folder: "Download" // Folder to save the downloaded file, if not exist it will be created
};
Downloader.download(options, downloadSuccessCallback, downloadErrorCallback);
} catch (e) {
console.log(e);
}
}
you can get the plugin here https://github.com/ogarzonm85/cordova-plugin-downloader
it Works and was too easy

Resources