Nuxt 3 file upload and store in locally in the project - file-upload

I want to create a simple Nuxt 3 file upload implementation that stores the file in the locally in a folder in the Nuxt project. In PHP the server side code is very easy and straight forward but I am finding it difficult doing the same thing in Nuxt 3 server side.

First:
npm install formidable
second:
define formidable in Nuxt config file inside modules list.
export default defineNuxtConfig({
modules: ["formidable"],
});
then in your handler for example upload.post.js :
import formidable from "formidable";
import fs from "fs";
import path from "path";
export default defineEventHandler(async (event) => {
let imageUrl = "";
let oldPath = "";
let newPath = "";
const form = formidable({ multiples: true });
const data = await new Promise((resolve, reject) => {
form.parse(event.req, (err, fields, files) => {
if (err) {
reject(err);
}
if (!files.photo) {
resolve({
status: "error",
message: "Please upload a photo with name photo in the form",
});
}
if (files.photo.mimetype.startsWith("image/")) {
let imageName =
Date.now() +
Math.round(Math.random() * 100000) +
files.photo.originalFilename;
oldPath = files.photo.filepath;
newPath = `${path.join("public", "uploads", imageName)}`;
imageUrl = "./public/upload/" + imageName;
fs.copyFileSync(oldPath, newPath);
resolve({
status: "ok",
url: imageUrl,
});
} else {
resolve({
status: "error",
message: "Please upload nothing but images.",
});
}
});
});
return data;
});
don't forget to name the input field "photo" in the client side or change it here in every "files.photo".
ALso the path of uploaded photos will be in public/uploads directory you can change it too if you like in "path.join" method.
Good luck

Related

How to create a .pdf or .csv file automatically in React Native for Android 11 (or later)

The following code works up to Android 10, it is creating a csv file in the DCIM folder:
import * as FileSystem from 'expo-file-system';
import * as MediaLibrary from 'expo-media-library';
export async function saveCSV() {
const permission = await MediaLibrary.requestPermissionsAsync();
if (permission.status != 'granted') {
console.log("Permission not Granted!")
return;
}
// CSVLocation
const directoryUri = FileSystem.documentDirectory;
const fileUri = directoryUri + `formData.csv`;
// Save to DCIM folder
const asset = await MediaLibrary.createAssetAsync(fileUri);
try {
const album = await MediaLibrary.getAlbumAsync('album');
if (album == null) {
console.log("ASSET", asset)
await MediaLibrary.createAlbumAsync('album', asset, true);
} else {
await MediaLibrary.addAssetsToAlbumAsync([asset], album, true)
.then(() => {
console.log('File Saved Successfully!');
})
.catch((err: string) => {
console.log('Error In Saving File!', err);
});
}
} catch (e) {
console.log(e);
}
}
Previously this line of code was executed in another function to create a file in the fileUri used above:
await FileSystem.writeAsStringAsync(fileUri, CSVheader + newInfo);
This issue has been described here: https://github.com/expo/expo/issues/12060
In short: Expo Media library is able to save image/video/audio assets so it will fail with other file types. Weirdly enough it was working fine with .pdf and .csv up to Android 10.
In the link above, and also on stackoverflow there are solutions using StorageAccessFramework. However, the user needs to create a subdirectory inside Downloads every time a file needs to be saved. I would like to make it automatically without any popups (after permission is granted).
The destination folder doesn't matter as long as it is accessible by the user later.

I am converting Images to pdf using a npm library in react native why it is giving error of null object?

I am using react-native-image-to-pdf library to convert images to pdf in my react native app. from https://www.npmjs.com/package/react-native-image-to-pdf
var photoPath = ['https://images.pexels.com/photos/20787/pexels-photo.jpg?auto=compress&cs=tinysrgb&h=350','https://images.pexels.com/photos/20787/pexels-photo.jpg?auto=compress&cs=tinysrgb&h=350'];
const myAsyncPDFFunction = async () => {
try {
const options = {
imagePaths: photoPath,
name: 'PDFName',
};
const pdf = await RNImageToPdf.createPDFbyImages(options);
console.log(pdf.filePath);
} catch(e) {
console.log(e);
}
}
but this is giving error Error: Attempt to invoke virtual method 'int android.graphics.Bitmap.getWidth()' on a null object reference
I have also tried giving path as ['./assets/a.png', './assets/b.png']
but still getting same error
Based on the usage example, your photoPath needs to be a local file path and not a remote path.
My recommendation is to first use rn-fetch-blob to download the remote image to the device, and then pass your new local image path to react-native-image-to-pdf. Something like:
RNFetchBlob
.config({
// add this option that makes response data to be stored as a file,
// this is much more performant.
fileCache : true,
})
.fetch('GET', 'http://www.example.com/file/example.png', {
//some headers ..
})
.then(async (res) => {
// the temp file path
console.log('The file saved to ', res.path())
const options = {
imagePaths: [res.path()],
name: 'PDFName',
};
const pdf = await RNImageToPdf.createPDFbyImages(options);
})
from file path remove the text 'file://; with empty string('').
const options = {
imagePaths: [uri.replace('file://', '')],
name: 'FileName',
quality: .9, // optional compression paramter
};
replace('file://', '') it's work for me

How can I specify the name of pdf print for react native project for iOS

I'm using both expo-print and expo-sharing to save file.
const { uri } = await Print.printToFileAsync({html});
await shareAsync(uri, { UTI: ".pdf", mimeType: "application/pdf" });
by default it is using UUID, I want to specify the file eg, abc.pdf, but I don't see the doc has any option to setup the file name.
I found the answer here
import * as Print from 'expo-print'
import * as Sharing from 'expo-sharing'
import * as FileSystem from 'expo-file-system'
const printToPdf = async () => {
const response = await Print.printToFileAsync({
html: createHtmlStringForPdf(),
})
// this changes the bit after the last slash of the uri (the document's name) to "invoice_<date of transaction"
const pdfName = `${response.uri.slice(
0,
response.uri.lastIndexOf('/') + 1
)}invoice_${readableDate.getTime()}.pdf`
await FileSystem.moveAsync({
from: response.uri,
to: pdfName,
})
sharePdf(pdfName)
}
const sharePdf = (url) => {
Sharing.shareAsync(url)
}

how to create pdf in react-native

I want to create pdf in my app in react-native for word to pdf or html to pdf converter.I have tried all possible react-native packages but none of them give me a desired result what should I do.
Are you using nodeJS on the server? If you are, send the html to the server and use this to convert the html to a pdf.
Have you Checked react-native-pdf-lib.
It is pretty good module.
Otherwise consider server side rendering
You can generate pdf file in react native with the npm package react-native-html-to-pdf.
Steps :
Create HTML template of your pdf file you want to generate.
Install the package and install pod in ios folder with pod install
Rebuild the app in android/ios.
import RNHTMLtoPDF from 'react-native-html-to-pdf';
const createPdf = async () => {
try {
let options = {
html: '<div>Hello pdf</div>',
fileName: 'demofile',
directory: 'Downloads',
base64: true,
};
let file = await RNHTMLtoPDF.convert(options);
console.log(file);
} catch (error) {
console.log(error);
}
}
Here is the more specific answer to your problem :
import RNHTMLtoPDF from 'react-native-html-to-pdf';
const createPdf = async () => {
let h1 = "Hey Heading 1";
let h2 = "heading 2";
let para = "Something description";
// use Backtick(`) to define html for your custom dynamic content
const pdf_html = `<div>
<h1>{h1}</h1>
<h1>{h2}</h1>
<h1>{para}</h1>
</div`;
try {
let options = {
html: pdf_html,
fileName: 'demofile',
directory: 'Downloads',
base64: true,
};
let file = await RNHTMLtoPDF.convert(options);
console.log(file);
} catch (error) {
console.log(error);
}
}

How to upload file to server using react-native

I am developing a app where i need to upload an image to the server. Based on the image i get a response which i need to render?.
Can you please help me how to upload an image using react-native?.
There is file uploading built into React Native.
Example from React Native code:
var photo = {
uri: uriFromCameraRoll,
type: 'image/jpeg',
name: 'photo.jpg',
};
var body = new FormData();
body.append('authToken', 'secret');
body.append('photo', photo);
body.append('title', 'A beautiful photo!');
var xhr = new XMLHttpRequest();
xhr.open('POST', serverURL);
xhr.send(body);
My solution is using fetch API and FormData.
Tested on Android.
const file = {
uri, // e.g. 'file:///path/to/file/image123.jpg'
name, // e.g. 'image123.jpg',
type // e.g. 'image/jpg'
}
const body = new FormData()
body.append('file', file)
fetch(url, {
method: 'POST',
body
})
I wrote something like that. Check out https://github.com/kamilkp/react-native-file-transfer
I have been struggling to upload images recently on react-native. I didn't seem to get the images uploaded. This is actually because i was using the react-native-debugger and network inspect on while sending the requests. Immediately i switch off network inspect, the request were successful and the files uploaded.
I am using the example from this answer above it works for me.
This article on github about the limitations of network inspect feature may clear things for you.
Just to build on the answer by Dev1, this is a good way to upload files from react native if you also want to show upload progress. It's pure JS, so this would actually work on any Javascript file.
(Note that in step #4 you have to replace the variables inside the strings with the type and file endings. That said, you could just take those fields out.)
Here's a gist I made on Github: https://gist.github.com/nandorojo/c641c176a053a9ab43462c6da1553a1b
1. for uploading one file:
// 1. initialize request
const xhr = new XMLHttpRequest();
// 2. open request
xhr.open('POST', uploadUrl);
// 3. set up callback for request
xhr.onload = () => {
const response = JSON.parse(xhr.response);
console.log(response);
// ... do something with the successful response
};
// 4. catch for request error
xhr.onerror = e => {
console.log(e, 'upload failed');
};
// 4. catch for request timeout
xhr.ontimeout = e => {
console.log(e, 'cloudinary timeout');
};
// 4. create formData to upload
const formData = new FormData();
formData.append('file', {
uri: 'some-file-path', // this is the path to your file. see Expo ImagePicker or React Native ImagePicker
type: `${type}/${fileEnding}`, // example: image/jpg
name: `upload.${fileEnding}` // example: upload.jpg
});
// 6. upload the request
xhr.send(formData);
// 7. track upload progress
if (xhr.upload) {
// track the upload progress
xhr.upload.onprogress = ({ total, loaded }) => {
const uploadProgress = (loaded / total);
console.log(uploadProgress);
};
}
2. uploading multiple files
Assuming you have an array of files you want to upload, you'd just change #4 from the code above to look like this:
// 4. create formData to upload
const arrayOfFilesToUpload = [
// ...
];
const formData = new FormData();
arrayOfFilesToUpload.forEach(file => {
formData.append('file', {
uri: file.uri, // this is the path to your file. see Expo ImagePicker or React Native ImagePicker
type: `${type}/${fileEnding}`, // example: image/jpg
name: `upload.${fileEnding}` // example: upload.jpg
});
})
In my opinion, the best way to send the file to the server is to use react-native-fs package, so install the package
with the following command
npm install react-native-fs
then create a file called file.service.js and modify it as follow:
import { uploadFiles } from "react-native-fs";
export async function sendFileToServer(files) {
return uploadFiles({
toUrl: `http://xxx/YOUR_URL`,
files: files,
method: "POST",
headers: { Accept: "application/json" },
begin: () => {
// console.log('File Uploading Started...')
},
progress: ({ totalBytesSent, totalBytesExpectedToSend }) => {
// console.log({ totalBytesSent, totalBytesExpectedToSend })
},
})
.promise.then(({ body }) => {
// Response Here...
// const data = JSON.parse(body); => You can access to body here....
})
.catch(_ => {
// console.log('Error')
})
}
NOTE: do not forget to change the URL.
NOTE: You can use this service to send any file to the server.
then call that service like the following:
var files = [{ name: "xx", filename:"xx", filepath: "xx", filetype: "xx" }];
await sendFileToServer(files)
NOTE: each object must have name,filename,filepath,filetype
A couple of potential alternatives are available. Firstly, you could use the XHR polyfill:
http://facebook.github.io/react-native/docs/network.html
Secondly, just ask the question: how would I upload a file in Obj-C? Answer that and then you could just implement a native module to call it from JavaScript.
There's some further discussion on all of this on this Github issue.
Tom's answer didn't work for me. So I implemented a native FilePickerModule which helps me choose the file and then use the remobile's react-native-file-transfer package to upload it. FilePickerModule returns the path of the selected file (FileURL) which is used by react-native-file-transfer to upload it.
Here's the code:
var FileTransfer = require('#remobile/react-native-file-transfer');
var FilePickerModule = NativeModules.FilePickerModule;
var that = this;
var fileTransfer = new FileTransfer();
FilePickerModule.chooseFile()
.then(function(fileURL){
var options = {};
options.fileKey = 'file';
options.fileName = fileURL.substr(fileURL.lastIndexOf('/')+1);
options.mimeType = 'text/plain';
var headers = {
'X-XSRF-TOKEN':that.state.token
};
options.headers = headers;
var url = "Set the URL here" ;
fileTransfer.upload(fileURL, encodeURI(url),(result)=>
{
console.log(result);
}, (error)=>{
console.log(error);
}, options);
})
Upload Files : using expo-image-picker npm module. Here we can upload any files or images etc. The files in a device can be accessed using the launchImageLibrary method. Then access the media on that device.
import * as ImagePicker from "expo-image-picker";
const loadFile = async () => {
let result = await ImagePicker.launchImageLibraryAsync({
mediaTypes: ImagePicker.MediaTypeOptions.All,
aspect: [4, 3],
});
return <Button title="Pick an image from camera roll" onPress={loadFile} />
}
The above code used to access the files on a device.
Also, use the camera to capture the image/video to upload by using
launchCameraAsync with mediaTypeOptions to videos or photos.