My original issue was it was getting the value when the user clicked on the compose button but not the send button.
I have now changed it to use a different new function when the user clicks send. However, now it's not doing anything.
Can someone tell me what I'm doing wrong? I used the onclick method in the HTML and then created the function on my Javascript page.
HTML:
<div id="compose-view">
<h3>New Email</h3>
<form id="compose-form"
method="POST">
{% csrf_token %}
<div class="form-group">
From: <input disabled class="form-control" value="{{ request.user.email }}">
</div>
<div class="form-group">
To: <input id="compose-recipients" class="form-control">
</div>
<div class="form-group">
<input class="form-control" id="compose-subject" placeholder="Subject">
</div>
<textarea class="form-control" id="compose-body" placeholder="Body"></textarea>
<input type="submit" id="sendEmail" class="btn btn-primary"/>
</form>
</div>
JS:
const element = document.getElementById('sendEmail');
element.addEventListener('click', function() {
fetch('/emails', {
method: 'POST',
body: JSON.stringify({
recipients: 'card51short#gmail.com',
subject: "buglets",
body: 'Hes a fat one'
})
})
.then(response => response.json())
.then(result => {
// Print result
console.log(result);
});
});
}
OK, in such cases you need to do an investigation of your code:
Check if fred is actually a string, and not undefined. Also, make it an explicit constant
const fred = document.querySelector('#compose-subject').value // changed
console.log(fred); // new
fetch('/emails', {
method: 'POST',
body: JSON.stringify({
recipients: 'card51short#gmail.com',
subject: fred,
body: 'Hes a fat one'
})
})
.then(response => response.json())
.then(result => {
// Print result
console.log(result);
});
If it's all good, do the next check of what is returned by the fetch:
const fred = document.querySelector('#compose-subject').value
fetch('/emails', {
method: 'POST',
body: JSON.stringify({
recipients: 'card51short#gmail.com',
subject: fred,
body: 'Hes a fat one'
})
})
.then(response => { // edited
console.log(response); // new
return response.json() // edited
}) // edited
.then(result => {
// Print result
console.log(result);
});
You should find what's not working by the end of this process
"value" attribute returns undefined for non input tags.
Try using innerHTML instead:
fred = document.querySelector('#compose-subject').innerHTML;
test your value for fred by cosole.log:
console.log(fred);
Related
I'm a newbie and i'm trying to create a rest project with Vue and Laravel and I have a form that allows to send an image, but when I try to store it in the db, I got an error:
"Request failed with status code 422"
and
"The image must be an image"
I can't figure how to solve it, any suggestion?
<script>
export default {
data() {
return {
title: undefined,
year: undefined,
director: undefined,
plot: undefined,
rating: undefined,
image: null,
};
},
methods: {
insertedFile(e) {
this.image = e.target.files[0];
},
addFilm() {
const formData = new FormData;
formData.set('image', this.image)
console.log(formData.get('image'));
//
axios
.post("/api/films", {
title: this.title,
year: this.year,
director: this.director,
plot: this.plot,
rating: this.rating,
image:formData
})
.then((response) => {
console.warn(response)
});
},
},
};
</script>
<template>
<form #submit.prevent="addFilm()" enctype="multipart/form-data" method="post">
<input type="text" name="title" placeholder="title" v-model="title" />
<input type="number" name="year" placeholder="year" v-model="year" />
<input
type="text"
name="director"
placeholder="director"
v-model="director"
/>
<input type="text" name="plot" placeholder="plot" v-model="plot" />
<input
type="number"
name="rating"
placeholder="rating"
v-model="rating"
/>
<input
type="file"
name="image"
id="image"
#change="insertedFile($event)"
/>
<button type="submit">Submit</button>
</form>
</template>
Controller:
public function store(Request $request)
{
$request->validate([
'title' => 'required',
'year' => 'required',
'plot' => 'required',
'director' => 'required',
'rating' => 'required',
'image' => 'image|mimes:jpg,png,jpeg,svg|max:2048'
]);
$film = new Film([
'title' => $request->title,
'year' => $request->year,
'plot' => $request->plot,
'director' => $request->director,
'rating' => $request->rating,
"image" => $request->file('image')->store('images', 'public')
]);
$film->save();
return redirect()->route('home')
->with('success', 'film created successfully!');
}
Try combining your payload (data) with your formData and setting the content-type header of your axios request to multipart/form-data:
const config = {
headers: {
'content-type': 'multipart/form-data'
}
}
let data = new FormData();
data.append('title', this.title);
data.append('year', this.year);
data.append('director', this.director);
data.append('plot', this.plot);
data.append('rating', this.rating);
data.append('image', this.image);
axios.post('api/films', data, config)
.then((response) => {
console.warn(response)
})
.catch((error) => {
console.log(error);
});
you're passing the FormData object as image.
in order to make it work, you should give axios the FormData object containing all the data you want to send.
addFilm method should look like this:
const formData = new FormData;
formData.append('image', this.image)
formData.append('title', this.title)
formData.append('year', this.year)
formData.append('director', this.director)
formData.append('plot', this.plot)
formData.append('rating', this.rating)
formData.append('image', this.image)
axios
.post("/api/films", formData)
.then((response) => {
console.warn(response)
});
I have a view which contains a form and looks like this,
<form class="flex-form" id="form" method="">
<div class="form-component">
<label>Type</label>
<input type="text" id="type" name="type">
</div>
<div class="form-component">
<div class="form-component"><label><b>Contents</b></label></div>
<label>Savoury</label><input type="text" name="savoury" id="savoury">
<label>Fillings</label><input type="text" name="fillings" id="fillings">
<label>Amount</label><input type="text" name="amount" id="amount">
<div class="flex-component">
<button class="set-button" type="button" id="set">Set Item</button>
</div>
</div>
<div class="form-component">
<label class="description-label">Description</label>
<textarea class="fixed-textarea" id="description" name="description" cols="15" rows="10"></textarea>
</div>
<div class="form-component">
<label >Unit Price</label>
<input type="text" id="price" name="unit_price">
</div>
<div class="flex-component">
<button class="form-button" type="submit">Add</button>
</div>
</form>
I have a JavaScript that allows me to capture some intermediary information (via the Set Item button) from the form before the form gets submitted (via the Add Button). I want to handle the form's submission from the script since I need to capture the intermediary data.
let collectedItems = [];
let setter = document.getElementById('set');
let form = document.getElementById('form');
setter.addEventListener('click',getSetContent);
function getSetContent() {
let type = document.getElementById('savoury');
let fillings = document.getElementById('fillings');
let amount = document.getElementById('amount');
const content = {
type: type.value,
fillings: fillings.value.split(','),
amount: Number(amount.value)
};
collectedItems.push(content);
clearInputFields([type,fillings,amount]);
}
function clearInputFields(inputFields) {
inputFields.forEach(field => {
field.value = ''
});
console.log(collectedItems);
}
form.addEventListener('submit',submitForm);
function submitForm() {
const type = document.getElementById('type').value;
const desc = document.getElementById('description').value;
const price = Number(document.getElementById('price').value);
const content = collectedItems;
const data = {
type: type,
contents: content,
description: desc,
unit_price: price
};
post('http://localhost:8001/add/box',
{ 'Content-Type': 'application/json' },
JSON.stringify(data)
);
}
function post(endpoint,header,body) {
const response = fetch(endpoint,{ method: 'POST',headers: header,body: body });
response.then(
resp => {
if (resp.ok) {
console.log('form submitted');
} else {
console.log('form not submitted');
}
}
)
}
I then make a POST request using fetch() to an endpoint I have setup in Express which looks like this,
app.post('/add/box',(req,res) => {
const box: any = req.body;
console.log(box);
// DO SOME DB STUFF
res.redirect('/');
});
The form submission works as intended (logs to terminal using nodemon), however I am unable to redirect to the homepage. Instead I stay on the form page after the submission has occurred and I can't figure out why. Any help with this issue is much appreciated.
Using Symfony Forms, HTML is generated that looks like this:
<input type="text" id="form_name" name="form[name]">
<input type="email" id="form_email" name="form[email]">
<textarea id="form_message" name="form[message]"></textarea>
With a bit of JS the entries are transformed to JSON and submitted:
const contactForm = document.getElementById('contact-form');
contactForm.addEventListener('submit', (event) => {
event.preventDefault();
const formData = new FormData(event.target);
const jsonData = JSON.stringify(Object.fromEntries(formData));
// handle submission...
})
JSON that is sent to the backend:
"{"form[name]":"John Doe","form[email]":"example#domain.com","form[message]":"Some message"}"
In my controller (in PHP) I serialize the data into an array: $data = json_decode($request->getContent()); The issue is this data is formatted (as expected) like so:
["form[name]" => "John Doe", "form[email]" => "example#domain.com", "form[message]" => "Some message"];
Is there a built-in way to get the following result (either in PHP or JS)?
[ "name" => "John Doe", "email" => "example#domain.com", "message" => "Some message" ];
I looked into using the Serializer Component without success, and now wonder if I missed something or if the data should be fixed in JS before submission. Might there be a built-in solution?
If I'm not wrong you are submitting from using AJAX. And in that you can directly specify FormData object as body in AJAX API request. At backend you will receive data in $_POST or $_GET array as per your request method.
Here is the example code.
const contactForm = document.getElementById('contact-form');
contactForm.addEventListener('submit', (event) => {
event.preventDefault();
const formData = new FormData(event.target);
fetch('<AJAX API URL>', {
method: 'POST',
body: formData
}).then(function (response) {
if (response.ok) {
return response.json();
}
return Promise.reject(response);
}).then(function (data) {
console.log(data);
}).catch(function (error) {
console.warn(error);
});
})
<form id="contact-form">
<input type="text" name="form['name']" />
<input type="text" name="form['job']" />
<input type="submit" value="submit" />
</form>
Here is how you will get data in POST array.
Array
(
[form] => Array
(
['name'] => 123
['job'] => 123123
)
)
I have a react page that looks like this:
and right now when creating a new category the post request goes through to the database but the categories is not rendered again to display the new category unless you refresh the page (GET request for all categories on page start up).
SideBar.js
createNewCategory = async (input) => {
console.log("CREATING NEW: ", input);
var response = await fetch("http://localhost:8081/api/categories", {
method: "POST",
headers: {
"Content-Type": "application/json",
"Token": 1234,
Accept: "application/json"
},
body: JSON.stringify({
title: input
})
})
let resp = await response.json();
this.setState({
categories: [...this.state.categories, resp]
})
}
CreateCategory.js
handleNewCategory = (event) => {
event.preventDefault()
this.props.createNewCategory(this.state.input)
this.setState({
input: ''
})
}
render(){
return (
<form onSubmit={this.handleNewCategory} className="new-category-form">
<h4>Create Category</h4>
<input onChange={this.handleInput} className="new-category-input" type="text" value={this.state.input} />
<input className="new-category-input" type="submit" value="Create" />
</form>
)
}
CategoriesContainer.js
function CategoriesContainer(props) {
function renderCategories(){
console.log("PROPS: ", props)
return props.categories.map(category => {
console.log("CATEACH: ", category)
return <Category key={category.id} category={category} />
})
}
return(
<div>
{renderCategories()}
</div>
)
}
At the moment if I create a new category with a name of letters I get the err
Uncaught (in promise) SyntaxError: Unexpected token a in JSON at position 0 sidebar.js:46
and if I create it with numbers I get
Warning: Each child in a list should have a unique "key" prop.
Im still new to react so hopefully Im not completely off the mark here, any ideas?
Fixed it. First off I was using response instead of resp to update the state and I was returning just the name rather than the whole object to the POST request.
Screenshot of UI
I'm having an issue invoking the inline javascript inside the mustache template file (.hjs).
when I click "Verify", the script tag and console logs do not run. It is not pulling the input code I type into the input box either.
For context: I am sending the mustache template (html) from my node server to an iFrame on the front end (React). I want the template to interact with the user and send an API call to my server and verify the 2FA.
I am sending variables to the javascript through {{ var }}, which is standard for mustache.
My thoughts: this code works in a regular index.html file.
any help or tips appreciated! I can try any suggestions locally to debug further.
<!DOCTYPE html>
<html>
<link rel="stylesheet" href="https://stackpath.bootstrapcdn.com/bootstrap/4.3.1/css/bootstrap.min.css" integrity="sha384-ggOyR0iXCbMQv3Xipma34MD+dH/1fQ784/j6cY/iJTQUOhcWr7x9JvoRxT2MZw1T" crossorigin="anonymous">
<body>
<div id="inline-widget" style="margin:0 auto;width: 360px;padding:5px">
<p style="font-family:-apple-system,BlinkMacSystemFont,'Segoe UI','Roboto','Oxygen','Ubuntu','Cantarell','Fira Sans','Droid Sans','Helvetica Neue',sans-serif;color:#48545d;font-size:14px;line-height:125%;margin:10px auto 20px;text-align:center">
Please complete your purchase by entering the 4 character code at the end of your recent charge description.
</p>
<img style="width: 350px;text-align:center;border:1px solid black" src="https://d2xxy1rwbjzckp.cloudfront.net/verification.jpeg" alt="Example"></img>
<p style="font-family:-apple-system,BlinkMacSystemFont,'Segoe UI','Roboto','Oxygen','Ubuntu','Cantarell','Fira Sans','Droid Sans','Helvetica Neue',sans-serif;color:#48545d;font-size:11px;line-height:125%;margin-bottom:10px auto 20px;text-align:left">
Code = 3122 in this example
</p>
<p id="error-message" style="font-family:-apple-system,BlinkMacSystemFont,'Segoe UI','Roboto','Oxygen','Ubuntu','Cantarell','Fira Sans','Droid Sans','Helvetica Neue',sans-serif;color:#48545d;font-size:11px;line-height:125%;margin-bottom:10px auto 20px;text-align:center;color:red"></p>
<div class="input-group mb-3">
<input id="2faCode" type="text" class="form-control" placeholder="4 digit code" aria-describedby="basic-addon2"/>
<div class="input-group-append">
<button class="btn btn-outline-secondary" id="verifyButton" type="button">Verify</button>
</div>
</div>
</div>
<script>
const button = document.getElementById('verifyButton');
button.addEventListener('click', async _ => {
try {
const verifyCode = document.getElementById('2faCode').value;
console.log('start!: ', verifyCode);
const response = await fetch({{ callbackUrl }}, {
method: 'post',
headers: {
'Accept': 'application/json',
'Content-Type': 'application/json'
},
body: JSON.stringify({
orderId: {{ orderId }},
verificationCode: {{ verifyCode }}
})
});
const contentType = response.headers.get("content-type");
if (contentType === 'text/html; charset=utf-8') {
const textResponse = await response.text();
document.getElementById("inline-widget").innerHTML = textResponse;
} else {
const parsedResponse = await response.json();
document.getElementById("error-message").innerHTML = parsedResponse.message;
}
} catch(err) {
document.getElementById("error-message").innerHTML = err;
console.error(`Error: ${err}`);
}
});
</script>
</body>
</html>