Having trouble writing form input to a separate file - javascript

Currently I have a Next.js app with a form that looks like this:
import React from 'react'
function Form() {
return (
<div>
<form action="/api/newfile" method="post">
<label htmlFor="project">project Name</label>
<textarea width={100} height={100} type="text" name="project" required />
<button type="submit">Submit</button>
</form>
</div>
)
}
export default Form
With help from How to create file from /api in NextJS? I was able to get an API function set up that my form can interact with:
import fs from 'fs';
export default async function handler(req, res) {
const {
method,
body,
} = req
try {
switch (method) {
case 'POST':
fs.writeFileSync('./pages/api/newfilewithoutanextension', JSON.stringify(body))
break
default:
res.setHeader('Allow', ['GET', 'POST'])
res.status(405).end(`Method ${method} Not Allowed`)
}
return res.status(200).json({ message: 'Success' })
} catch (error) {
return res.status(500).json(error)
}
}
I fire up the app and at the /form page my input looks like this:
function() {
echo my form input
}
I am able to write my new file to disk without the file extension (this was correct by design), however the response is written in JSON. It looks like this:
{"project":"function() {\r\n echo \"my form input\"\r\n}"}
I need the newly generated file contents to look like that of my form input.
I have tried replacing the JSON.stringify(body) but seem to get everything but the response I need.

Related

Django and React : [ErrorDetail(string='The submitted data was not a file. Check the encoding type on the form.', code='invalid')]

I am gettting the error: [ErrorDetail(string='The submitted data was not a file. Check the encoding type on the form.', code='invalid')], for submitting an image/file.
I added the encryption type for the form 'multipart/form-data' same thing in Axios call too, but I still get the same error.
I have a model like this:
class MyModel(models.Model):
img = models.ImageField(upload_to='media',blank=False)
In views.py:
class MyModelView(viewset.ModelViewSet):
serializer_class = serializer.MyModelSerializer
def post(self,request):
data = serializer.MyModelSerializer(data=request.data)
print(data.is_valid()) # this is false, means there is an error
print(data.errors) #This one will display the error shown in the title of this question
if data.is_valid():
img = data.data['img']
return Response('Success')
return Response('Fail')
In serializer.py:
class MyModelSerializer(serializers.ModelSerializer):
class Meta:
model = MyModel
fields = '__all__'
In frontend side (React):
function ImgComp(){
let [img,setImg] = useState({'image':''}
let {image} = img
function handleChange(e){
setImg(
{
...img,[e.target.name]:e.target.value
}
)
}
function submitForm(e){
e.preventDefault()
axios.post('127.0.0.1:8000/mymodelurl/',img,{withCredentials:true,headers:{'Content-Type':'multipart/form-data'}})
return(
<div>
<form method='post' encType='multipart/form-data' onSubmit = {(e)=>submitForm(e)}>
<input type='file' value={image} name='img' onChange={(e)=>handleChange(e)}/>
</form>
</div>
}
}
If I debug the img I get something like:
C:\\fakepath\\img.png

vue + nuxt.js - How to read POST request parameters received from an external request

I have a an external form which submits a post request to my nuxt app. I am struggling currently to find out how I can access these POST request parameters in my nuxt page?
I found so far the "asyncData" method, but when I try to access the submitted parameter through the "params" object it is always "undefined". What do I wrong here?
"asyncData" nuxt reference
example code in my nuxt page, assuming "email" is the request parameter submitted from outside
export default {
asyncData({ params }) {
console.log('asyncData called...' + params.email);
return {email: params.email};
},
external html form
<body>
<form action="https://..." target="_blank" method="post">
<input name="email" class="input" type="text" placeholder="Email" maxlength="255"></input>
<input name="submit" class="btn" type="submit" value="Ok"></input>
</form>
</bod>
I found a way, as described in "asyncData" nuxt reference you can pass the request and response object to the "asyncData({req,res})" call.
Here an example - assuming 'email' is one of the post parameter. querystring is a module of node.js and allows you to parse the request body into an array.
Small Remark - this seems only to work for nuxt page level components but not for lower level components
<script>
export default {
asyncData({ req, res }) {
if (process.server) {
const qs = require('querystring');
var body = '';
var temp = '';
while(temp = req.read()) {
body += temp;
}
var post = qs.parse(body);
return {data: post};
}
},
data() {
return {
data: '',
}
},
mounted() {
console.log(this.data['email']);
},
</script>
Nuxt.js cannot handle such things by itself.
https://nuxtjs.org/api/configuration-servermiddleware
You should implement your own middleware for such cases.
And asyncData has nothing to do with handling inbound POST data.

Angular 4 and Nodejs http post request implementation error

I created small test application using Angular 4 and Nodejs. I want to insert a text field value to the database either Mongo or mysql.
Following files I created server.js for running nodejs, Created server>router folder with another file api.js and Angular 4 user component created.
What i did code shown below
user.component.html
<form (submit)="addHobby(hobbies,hobby.value)">
<input type="text" #hobby>
<input type="submit" value="Submit">
</form>
user.component.ts
addHobby(arrHob,hobby) {
if(arrHob.indexOf(hobby) == -1) {
this.hobbies.unshift(hobby);
this.dataService.postHobby(hobby).subscribe((posts) => {
console.log(posts);
})
}
return false;
}
Services folder contain data.service.ts
postHobby(hobby) {
return this.http.post('/api/insertHobby',hobby).map(res => res.json().data);
}
server router folder contain api.js
router.post('/insertHobby', (req, res) => {
console.log("Welcome to post method");
console.log(req.body.data);
})
When form submitting i'm getting output as only welcome to post method
req.body.data i'm getting as *'Undefined'* How to resolve this issue. Any way thanks to everyone..
since you are not passing the variable as object , you need to pass it in object format as below :
postHobby(hobby) {
return this.http.post('/api/insertHobby',{hobby: hobby}).map(res => res.json().data);
}

Upload and read a file in react

Im trying to upload a file with React and see its contents, but what it gives me is C:\fakepath\. I know why it gives fakepath, but what is the correct way to upload and read the contents of a file in react?
<input type="file"
name="myFile"
onChange={this.handleChange} />
handleChange: function(e) {
switch (e.target.name) {
case 'myFile':
const data = new FormData();
data.append('file', e.target.value);
console.log(data);
default:
console.error('Error in handleChange()'); break;
}
},
To get the file info you want to use event.target.files which is an array of selected files. Each one of these can be easily uploaded via a FormData object. See below snippet for example:
class FileInput extends React.Component {
constructor(props) {
super(props)
this.uploadFile = this.uploadFile.bind(this);
}
uploadFile(event) {
let file = event.target.files[0];
console.log(file);
if (file) {
let data = new FormData();
data.append('file', file);
// axios.post('/files', data)...
}
}
render() {
return <span>
<input type="file"
name="myFile"
onChange={this.uploadFile} />
</span>
}
}
ReactDOM.render(<FileInput />, document.getElementById('root'));
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/15.6.1/react.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/15.6.1/react-dom.min.js"></script>
<div id="root"></div>
You may want to look into FileReader which can help if you want to handle the file on the client side, for example to display an image.
https://developer.mozilla.org/en-US/docs/Web/API/FileReader
You can use React Dropzone Uploader, which gives you file previews (including image thumbnails) out of the box, and also handles uploads for you.
In your onChangeStatus prop you can react to the file's meta data and the file itself, which means you can do any kind of client-side processing you want before or after uploading the file.
import 'react-dropzone-uploader/dist/styles.css'
import Dropzone from 'react-dropzone-uploader'
const Uploader = () => {
return (
<Dropzone
getUploadParams={() => ({ url: 'https://httpbin.org/post' })} // specify upload params and url for your files
onChangeStatus={({ meta, file }, status) => { console.log(status, meta, file) }}
onSubmit={(files) => { console.log(files.map(f => f.meta)) }}
accept="image/*,audio/*,video/*"
/>
)
}
Uploads have progress indicators, and they can be cancelled or restarted. The UI is fully customizable.
Full disclosure: I wrote this library.
Try to use Multer and gridfs-storage on the back end and store the fileID along with your mongoose schema.
// Create a storage object with a given configuration
const storage = require('multer-gridfs-storage')({
url: 'MONGOP DB ATLAS URL'
});
// Set multer storage engine to the newly created object
const upload = multer({ storage }).single('file');
router.post('/', upload, (req, res) => {
const newreminder = new Reminders({
category: req.body.category,
name:req.body.name,
type: req.body.type,
exdate: req.body.exdate,
location:req.body.location,
notes:req.body.notes,
fileID: req.file.id
});
newreminder.save(function(err){
if(err){
console.log(err);
return;
}
res.json({ "success": "true"});
});
});
Then on the front end treat it normally (with Axios) and upload the entire file and grab a hold of all the info in the normal react way:
onSubmit = (e) => {
e.preventDefault;
const formData = new FormData();
formData.append({ [e.target.name]: e.target.value })
formData.append('file', e.target.files[0]);
axios.post({
method:'POST',
url:'EXPRESS JS POST REQUEST PATH',
data: formData,
config:{ headers: {'Content-Type':'multipart/form-data, boundary=${form._boundary}'}}
})
.then(res => console.log(res))
.catch(err => console.log('Error', err))
}
Have you use dropzone ?
see this react-dropzone
easy implement, upload and return url if this important.
onDrop: acceptedFiles => {
const req = request.post('/upload');
acceptedFiles.forEach(file => {
req.attach(file.name, file);
});
req.end(callback);
}
You can use FileReader onload methods to read the file data and then can send it to the server.
You can find this useful to handle files using File Reader in React ReactJS File Reader
To add to the other answers here, especially for anyone new to React, it is useful to understand that react handles forms a little differently than people may be used to.
At a high level, react recommends using 'Controlled components" :
In most cases, we recommend using controlled components to implement forms. In a controlled component, form data is handled by a React component. The alternative is uncontrolled components, where form data is handled by the DOM itself.
This essentially means that the user input, e.g. a text field, is also a state of the component and as the user updates it the state is updated and the value of the state if displayed in the form. This means the state and the form data are always in synch.
For an input type of file this will not work because the file input value is read-only. Therefore, a controlled component cannot be used and an 'uncontrolled component' is used instead.
In React, an is always an uncontrolled component because its value can only be set by a user, and not programmatically.
The recommended way to input a file type (at the time of writing) is below, from the react documentation here https://reactjs.org/docs/uncontrolled-components.html#the-file-input-tag:
class FileInput extends React.Component {
constructor(props) {
super(props);
this.handleSubmit = this.handleSubmit.bind(this);
this.fileInput = React.createRef();
}
handleSubmit(event) {
event.preventDefault();
alert(
`Selected file - ${this.fileInput.current.files[0].name}`
);
}
render() {
return (
<form onSubmit={this.handleSubmit}>
<label>
Upload file:
<input type="file" ref={this.fileInput} />
</label>
<br />
<button type="submit">Submit</button>
</form>
);
}
}
ReactDOM.render(
<FileInput />,
document.getElementById('root')
);
The documentation includes a codepen example which can be built on.

Sending a CSV file using Node/Express

I'm building a front end tool that allows users to upload a CSV file to a certain end point. I use the HTML5 input="file"
Here is my JSX, I use the React Dropzone library:
<Dropzone
multiple={false}
onDrop={this.onDrop}
>
<div>
<input type="file" />
</div>
</Dropzone>
The onDrop function:
onDrop(acceptedFile) {
this.setState({ file: acceptedFile });
}
I grab that file and put it on my state. My submit function looks like this:
submitFile() {
const formData = new FormData();
formData.append('uploadCsv', this.state.file);
fetch('/api/person/uploadfile', {
body: formData,
method: 'POST'
});
}
It then goes through a few files for routing..
router.use('/person', require('./routers/personRoutes').default);
router.post('/uploadfile', fileUpload);
Then I run my fileUpload function:
export const fileUpload = post({
route: req => {
return `${BASE_URL}/v1/fileupload/persons`;
}
});
Here I have no idea what to do. Usually I just have to return a URL and everything works. req.body is just an empty object - {}. The error message I get back says:
Current request is not a multipart request
BUT. Something as simple as this does work:
<html>
<form action="http://localhost:9275/v1/fileupload/persons"
enctype="multipart/form-data" method="post">
<p>
Please specify a file, or a set of files:<br>
<input type="file" name="file" size="40">
</p>
<div>
<input type="submit" value="Send">
</div>
</form>
</html>
I've looked all over stack overflow and none of solutions have helped thus far :( the coworker who wrote the node stuff left so I'm alone on this

Categories

Resources