I have a basic Netlify form (based on this guide) with name, email and message fields. With the following submit function:
const handleSubmit = event => {
event.preventDefault();
const data = {};
const scopedForm = [...formState];
let isValidForm = validateForm(scopedForm);
setFormState([...scopedForm]);
if (!isValidForm) return false;
formInputs.forEach(input => data[input.name] = input.value);
fetch(`/`, {
method: `POST`,
headers: {
'Accept': `application/x-www-form-urlencoded;charset=UTF-8`,
'Content-Type': `application/x-www-form-urlencoded`,
},
body: encode({
'form-name': `Contact Form`,
...data,
}),
})
.then(() => console.log(`OK`))
.catch(error => alert(error));
};
const encode = data => {
return Object.keys(data)
.map(key => encodeURIComponent(key) + `=` + encodeURIComponent(data[key]))
.join(`&`);
};
Pretty simple, besides the validations, I create a data object and I fill it with a pair of data[input.name] = input.value. Everything works as expected locally, as well as in develop and build mode. I can see a POST request, however, in production, it turns into a GET:
I've tried changing the built-in fetch to axios but the result is the same. I don't know if I need to add some custom configuration in my server or how to bypass this.
My resulting HTML structure is:
<form name="Contact Form" method="POST" action="/" data-netlify="true" data-netlify-honeypot="bot-field" data-netlify-recaptcha="true">
<div><label for="form-name"><input type="hidden" name="form-name" value="Contact Form"></label></div>
<div><label for="bot-field"><input type="hidden" name="bot-field" value=""></label></div>
<div><label for="name">Name:<input type="text" name="name" value="Chancellor Lawson"></label></div>
<div><label for="email">Email:<input type="text" name="email" value="fivyhohy#mailinator.com"></label></div>
<div><label for="message">Message:<textarea name="message">Ea quisquam ea vel e</textarea></label></div>
<button type="submit">Send</button>
</form>
I have read a lot of similar issues, articles, and guides but none helped.
In order to close the issue, I will answer my own question, giving all the merits to Quentin. As he pointed out, the solution was removing the Accept header since it only was accepting application/x-www-form-urlencoded;charset=UTF-8 requests. So the header should look like:
headers: {
'Content-Type': `application/x-www-form-urlencoded`,
},
From MDN documentation:
The Accept request HTTP header advertises which content types,
expressed as MIME types, the client is able to understand. Using
content negotiation, the server then selects one of the proposals,
uses it and informs the client of its choice with the Content-Type
response header. Browsers set adequate values for this header
depending on the context where the request is done: when fetching a
CSS stylesheet a different value is set for the request than when
fetching an image, video, or script.
Related
I did a build along to make a twitter tweet box. It has html css and js. The character count portion seems to work great. But when I try to send the value of the text area as a POST request, the json payload comes back as None. When I hit the server from Postman, it seems to work just fine. I don't know how much of the code I should include. So please let me know. I don't want to put the whole thing and make it unreadable. I'll include the parts I think make sense to include.
<div class="wrapper">
<form action="{{ url_for('thread_builder') }}" method="post">
<div class="input-box">
<div class="tweet-area">
<span class="placeholder">What's happening?</span>
<div class="input editable" contenteditable="true" spellcheck="false"></div>
<div id="text" class="input readonly" contenteditable="true" spellcheck="false"></div>
</div>
const textarea = document.getElementById("tweet-area");
const button = document.getElementById("tweetButton");
const counter = document.getElementById("counter");
const readonlyInput = document.getElementById("readonlyInput");
const maxLength = 280;
button.addEventListener("click", function() {
let text = textarea.value;
let currentLength = text.length;
if (currentLength <= maxLength) {
// send text to the server using fetch
fetch('/thread_builder', {
method: 'POST',
headers: {
'Content-Type': 'application/json'
},
body: JSON.stringify({ "text": text })
})
.then(response => response.json())
.then(data => {
// handle the response from the server here
})
.catch(error => {
// handle error here
});
}
I tried sending the POST request from POSTMAN and it worked great. I've tried check what type of information is being sent, and I was expecting a string with what was entered in the text box.enter code here
I'm trying to see if it is possible to upload an image from the <img src=""> to a database, without using the input function
<form class="form-horizontal" validate="true" action="upload1.php" method="POST" enctype="multipart/form-data">
<a href="javascript:void(0)" class="closebtn" onclick="closeForm()"</a>
<img id="output" src="name.png" data-name="photo" width="100%"/>
<input type="hidden" name="photo" id="output" value="">
<input type="submit" name="reg" value="Update Status" class="btn btn-solid">
</form>
I just want to know if there's a way it could work
I am not sure why you do not want to use an input field, since this makes the image upload easier and also provides you a File object which inherits from a Blob and provides you info about the image like filename, lastModified, etc (see more here).
Regardless, yes this is possible in javascript using FormData. However, you would have to either convert the image to base64 (which I do not recommend because this makes the size about 33% larger), or use a Blob object and upload that (which also involves a hacky workaround using fetch). Here is an example of what you could do.
// Convert img to Blob
const img = document.getElementById('output');
fetch(img.src)
.then(res => res.blob())
.then(blob => {
// Prepare image for upload
const fd = new FormData();
fd.append('uploadedImage', blob, 'tmp.png');
// Upload
fetch(<image-upload-endpoint>, {
method: 'POST',
body: fd
})
.then(res => {
if (res.ok) {
// Upload was successful
} else {
// Upload failed
}
});
});
Then you would be able to retrieve the file in PHP with $_FILES['uploadedImage']
I am trying to recreate google translate, I have an api which sends data as expected, also returns data as expected the first time. After changing text and trying to translate it, it sends the changed text but returns old data from the first api request.
Here's the code:
const encodedParams = new URLSearchParams();
const inputClick = (key) => {
console.log("input key is: ", key)
encodedParams.append("from", key)
};
const outputClick = (key) => {
console.log("output key is: ", key)
encodedParams.append("to", key)
};
const options = {
method: "POST",
headers: {
"content-type": "application/x-www-form-urlencoded",
"X-RapidAPI-Key": "...",
"X-RapidAPI-Host": "translo.p.rapidapi.com",
},
body: encodedParams,
};
const translate = () => {
let inp = document.getElementById("input-txt").value;
encodedParams.append("text", inp)
console.log("input text: ", inp)
fetch("https://translo.p.rapidapi.com/api/v3/translate", options)
.then((response) => response.json())
.then((response) => {
console.log(response)
console.log("translated text: ", response.translated_text)
})
.catch((err) => console.error(err))
}
Here's the data it returns:
input key is language I am translating FROM (here it is bosnian),
output key is language I am translating TO (here it is english),
first input text is correct and should translate to "Greetings from Bosnia" which it does,
second input text is modified and correct which should translate to "Greetings from Croatia" which it does not translate to.
I am out of ideas.
EDIT
encodedparams is declared on start I just failed to copy it correctly
Here's extra code
Following code is for inputClick, this is where I choose one of the languages from dropdown menu, the languages.map is extracting array of available languages from other js file which I imported. the language.code is ISO 639-1 code for selected language:
<ul className="dropdown-menu">
{languages.map((language) => (
<li>
<button
className="dropdown-item"
type="button"
onClick={() => inputClick(language.code)}
key={language.code}
>
{language.name}
</button>
</li>
))}
</ul>
Following code is for input text, this is where I type text that I want to be translated which is obtained with getElementById:
<div className="input-txt layout">
<textarea
type="text"
id="input-txt"
placeholder="Unesite vaš tekst ovdje..."
/>
</div>
Following code is outputClick, same explanation as inputClick just for output:
<ul className="dropdown-menu">
{languages.map((language) => (
<li>
<button
className="dropdown-item"
type="button"
onClick={() => outputClick(language.code)}
key={language.code}
>
{language.name}
</button>
</li>
))}
</ul>
Following code is for button which calls translate() on click:
<button
type="button"
className="btn btn-dark trans-btn"
onClick={() => translate()}
>
Prevedi
</button>
*Prevedi means Translate
Problem has been solved by going into Network and seeing what was exactly going to api, the following image will make you understand better:
When sending the first time the text is APPENDED to encodedParams and is sent correctly. The problem lies when I APPEND another text without clearing previous one which creates problem where both texts are sent, and if I change the text for the third time the last two texts are sent with the new one and just goes on and on, you can see it in this image:
Seems like api only takes first text and doesn't go to the last one and take that instead.
Anyways this problem is solved by clearing the appended text after fetch by adding next line:
encodedParams.delete("text", inp)
The function looks like this now:
I have problem with implementation of 3ds verification for Recurly, i have followed example from https://github.com/recurly/recurly-js-examples/blob/master/public/3d-secure/authenticate.html
My problem is that first iframe is loading correctly, but after clicking "
Succeed Test Authentication" returns nothing to my threeDSecure.on('token' funcition(){}). It loads iframe with information "To complete your checkout process, please close this browser tab and return to your checkout form." Thanks for any responses.
My view file
https://pastebin.com/irCuGr48
<form id="pm-recurly-form-3ds" method="post" action="<?php echo esc_url( get_permalink( get_queried_object_id() ) ); ?>subscription/pay/">
<div id="container-3ds-authentication" class="three-d-secure-auth-container col-12 " ></div>
<div class="three-d-secure-submitting-messagge col-12">
Authenticating your payment method...
</div>
<?php wp_nonce_field( 'pm-register-subscription-nonce' ); ?>
<input type="hidden" name="pm-form-request" value="register-subscription" />
<input type="hidden" name="pm-price-plan" value="<?php echo esc_attr( $pm_price_plan ); ?>">
<input type="hidden" name="three-d-secure-token" id="three-d-secure-token" value="">
<input type="hidden" name="recurly-token" id="recurly-token" value="">
</form>
My JS file
https://pastebin.com/7zYDAEJs
// We expect this page to load with the following parameter pattern
// `/3d-secure.html#token_id=xxx&action_token_id`
// This is a simple parser for that pattern. You may use window.URLSearchParams
// instead if IE11 support is not needed
var hashParams = location.hash.substr(1).split('&').reduce(function (acc, i) {
var [k,v] = i.split('=');
acc[k]=v;
return acc;
}, {});
// Configure Recurly.js
recurly.configure(recurly_key);
// In order to remain backend agnostic, this example passes the Recurly.js credit card token
// to this page via the URL hash. Here we add it to the form so that it will be passed
// to our backend
document.querySelector('#recurly-token').setAttribute('value',hashParams.token_id);
// Now we construct the 3-D Secure authentication flow
var risk = recurly.Risk();
var threeDSecure = risk.ThreeDSecure({ actionTokenId: hashParams.action_token_id });
var container = document.querySelector('#container-3ds-authentication');
// Handle errors that occur during 3-D Secure authentication
threeDSecure.on('error', error);
// 'token' is called when your user completes the 3-D Secure authentication flow
threeDSecure.on('token', function (token) {
console.log(token);
// place the result token in your form so that it will be submitted
// when the customer re-submits
document.querySelector('#three-d-secure-token').setAttribute('value',token.id);
// Hide the container once we have a token
container.style.display = "none";
// Show the loading message
document.querySelector('.three-d-secure-submitting-messagge').style.display = "block";
// submit the form automatically
recurly_form_verify.submit();
});
// Attach our 3D Secure session to the container
threeDSecure.attach(container);
// Show the container
container.style.display = "block";
// runs some simple animations for the page
document.querySelector('body').classList.add( 'show' );
Second iframe
Resolved via issue in recurly-js repo:
https://github.com/recurly/recurly-js/issues/553
I have been searching for a solution for this but none of the guides are updated or suited for my intention. I need a user uploaded image to be loaded into javascript/aurelia which then sends it to the asp.net core backend using its http fetch client so the image is saved on disk(not in a database). I'm currently using the following code but I'm getting the following error and no images are being saved.
extract from html code being used to upload image
<input class="hiddenButton" id="images" type="file" accept=".jpeg" file.bind="image">
<button class="upload" onclick="document.getElementById('images').click()">
<i class="fa fa-pencil" style="color:green"></i>
</button>
extract of javascript code used to invoke saving
save() {
this.api.saveEmployee(this.employee).then(employee => this.employee = employee);
this.ea.publish(new EmployeeAdded(this.employee));
this.api.saveImage(this.image);
return this.employee;
}
Javascript/aurelia code
saveImage(image) {
var form = new FormData()
form.append('image', image)
this.http.fetch('/api/Images', {
method: 'POST',
//headers: { 'Content-Type': image.type },
body: form
})
.then(response => {
return response
})
.catch(error => {
console.log("Some Failure...");
throw error.content;
})
return true;
}
Asp.net core MVC code(backend)
[HttpPost]
public async Task<IActionResult> SaveImage(IFormFile file)
{
Console.WriteLine("Images controller");
var filePath = Path.Combine(Directory.GetCurrentDirectory(),"Image");
using (var stream = new FileStream(filePath, FileMode.Create))
{
await file.CopyToAsync(stream);
}
return Ok();
}
error message
The HTML element <input type="file" /> does not have a property file, the correct property is files, so it sounds like the problem is with aurelia/javascript and binding.
Since the property files is a FileList (collection) you will need to access the first file in the collection. Even though you haven't used multiple I think files will still be a collection.
You could try this:
// html
<input class="hiddenButton" id="images" type="file" accept=".jpeg" files.bind="image">
// ^ files
// jss/aurelia
saveImage(image) {
var form = new FormData();
form.append('image', image[0]); // access the first image in collection image[0]
// the other code remains the same
//...
}
PS I haven't used aurelia so can't be 100% sure this is the issue but hopefully points you in the correct direction.
PPS: since files is a collection, technically image in your view model is a collection too, so you could consider renaming it to images to make it clearer (even if you're only using one image). It should still work using image[0] but images[0] would be clearer.