PUT XMLHttpRequest returns an empty at console - javascript

I am trying to send a PUT request through XMLHttpRequest but it return an empty using JS for the front end and nodejs for the backend. while in the network section in the dev tools, it shows that PUT is ok . I have been dealing with this for over 10 days, every iota of support will be highly appreciated. I really need this as I don't know what to do next. It's driving me nuts.
Below is my html
<body>
<form action="location.js" id="myLocation" method="PUT">
<br>
<div>
<label> location </label>
<input id="location" type="text" name="location" required>
</div>
<br>
<div>
<button type=submit>submit</button>
</div>
</form>
<div id="locate">
</div>
GO TO LOGIN
<script src="location.js"> </script>
<script src=""> </script>
</body>
Next is the JS for XMLHttpRequest
var form = document.getElementById('myLocation');
var display = document.getElementById('locate');
form.addEventListener('submit', sendData);
function sendData(e) {
e.preventDefault();
var location = document.getElementById('location').value;
var params = JSON.stringify({
"location": location
});
var val = params;
const XHR = new XMLHttpRequest();
XHR.onload = function () {
var out1 = this.responseText;
display.innerHTML = out1;
console.log(out1);
};
XHR.open('PUT', 'http://localhost:5000/parcel/:id/location', true);
XHR.setRequestHeader('Content-type', 'application/json; charset=utf-8');
XHR.setRequestHeader('Method', 'PUT');
XHR.send(val);
}
Below is the API router for the PUT request:
router.put('/:id/location', async (req, res) => {
res.setHeader("Access-Control-Allow-Origin", "http://localhost:8080");
res.setHeader("Access-Control-Allow-Headers", "Content-Type, application/json;charset=utf-8");
res.setHeader("Access-Control-Allow-Method", "PUT");
let parcels
try {
const {_id} = req.params.id;
const {location} = req.body.location;
parcels = await parcel.findByIdAndUpdate(_id, location);
res.send(parcels);
} catch (err) {
console.log(err);
if (parcels == null) {
res.send('error nul')
} else{
res.send('unsuccesful')
}
}
});

XHR.open('PUT', 'http://localhost:5000/parcel/:id/location', true);
I think that :id is not right here.
Edit:
:id is a "route parameter". The listener can use it to cover a range of routes.
So if your API gets a GET request on /parcel/0001/location or /parcel/asd/location then the /parcel/:id/location handler can respond to all of them, and you can read the id from req.params.id.
You can only use this feature if you already know :id on the client side, and you can build it into the route e.g: "http://localhost:5000/parcel/"+id+"/location".

Related

Append antiforgery token to XMLHttpRequest

Pretty much what the title says. Here's the javascript... Works fine when not validating the token. Doesn't appear to see it when validating as I get The required anti-forgery form field "__RequestVerificationToken" is not present. error.
var downloadEmailSignature = function (control) {
if (control) {
let form = $(control).closest('form');
let token = $(form).find('input[name="__RequestVerificationToken"]').val();
if (form) {
let request = new XMLHttpRequest();
request.open("POST", "Forms/DownloadEmailSignature");
request.responseType = "blob";
request.setRequestHeader('RequestVerificationToken', token);
request.data = form.serialize();
request.onload = function () {
if (window.clientData.browser.name === "Internet Explorer") {
window.navigator.msSaveBlob(this.response, "EmailSignature.hta");
}
else{
let url = window.URL.createObjectURL(this.response);
let a = document.createElement("a");
document.body.appendChild(a);
a.href = url;
a.download = this.response.name || "download-" + $.now();
a.click();
}
};
console.dir(request);
request.send();
}
}
};
and the code behind...
[HttpPost]
[ValidateAntiForgeryToken]
public ActionResult DownloadEmailSignature(string emailSignature)
{
var hta = (MediaItem)SitecoreContext.GetItem<Item>(new Guid("{EE806F14-5BD3-491C-9169-DA701357FB45}"));
using (var reader = new StreamReader(MediaManager.GetMedia(hta).GetStream().Stream))
{
var htaText = reader.ReadToEnd();
htaText = htaText.Replace("*CARDSTRING*", emailSignature);
var stream = new MemoryStream(htaText.ToASCIIByteArray());
return new FileStreamResult(stream, "application/hta");
}
}
And finally the view...
<form id="download-email-signature" method="POST" enctype="multipart/form-data">
#Html.HiddenFor(m => m.EmailSignatureMarkup)
#Html.AntiForgeryToken()
#Html.FormIdentifier("FormsController", "DownloadEmailSignature")
Download installer
</form>
If you can replace XMLHttpRequest with $.ajax (as you already have JQuery loaded), the below segment should work.
let form = $(control).closest('form');
let token = $(form).find('input[name="__RequestVerificationToken"]').val();
$.ajax({
url: '/Home/DownloadEmailSignature',
type: 'POST',
data: {
__RequestVerificationToken: token,
emailSignature: 'emailSignature value'
},
success: function (result) {
alert(result);
//your code ....
}
});
According to the answer here:
ValidateAntiForgeryToken purpose, explanation and example
MVC's anti-forgery support writes a unique value to an HTTP-only
cookie and then the same value is written to the form. When the page
is submitted, an error is raised if the cookie value doesn't match the
form value.
Which implies the cookie MUST go back to the server. This should be working fine unless you are using IE9 (which is known to be problematic with this issue).
I recommend you include request.withCredentials = true; to eliminate any strange CORs related issue.
If a proxy is involved, the cookie may be getting stripped on the way back to the server too.

How to call existing REST api from a HTML form?

I have a REST API that I am using in a mobile application to register/store data into a Mongo database. I would now like to view the data stored in the DB on a webpage.
I know that I basically have all of the functionality already (the login request used in my mobile application) but I am so confused on how to call my REST from my HTML page.
Something like this: How to call a REST web service API from Javascript button Handler? ?
I am also confused on how/where I should be creating my html page. Any help is appreciated.
Thanks, Joe
Typically When user would like to get data from the server. client need to send a request to the server and get a response. Usually programmer will bind a request function with an specific element and events.
In this case you need to bind a request function with form element. As you didn't mention which event you want to happen, so I couldn't tell exactly solution.
The following code is a simple code that call REST API when user type on a text input, and show the result below the input text
Note that replace "URL" with your API call.
<!DOCTYPE html>
<html>
<body>
<form>
Keyword:<br>
<input type="text" name="keyword" onkeyup="callREST()"><br>
</form>
<div id="response"></div>
<script>
function callREST() {
var xhttp = new XMLHttpRequest();
xhttp.onreadystatechange = function() {
if (this.readyState == 4 && this.status == 200) {
document.getElementById("response").innerHTML = this.responseText;
}
};
xhttp.open("GET", "URL", true);
xhttp.send();
}
</script>
</body>
</html>
This is how you do it...
HTML Code:
<form id="form" onsubmit="return setAction(this)">
<input name="senderEmail" type="email" placeholder="Email" required>
<textarea name="senderMessage" cols="30" rows="10" placeholder="Message.." required></textarea>
<button type="submit">Send message</button>
</form>
Javascript:
function setAction(form) {
const url = 'https://example.com/xyz?';
const andSign = '&';
const senderParameter = 'sender='+form.senderEmail.value;
const bodyParameter = 'body='+form.senderMessage.value;
const newUrl = url+senderParameter+andSign+bodyParameter;
fetch(
newUrl,
{
headers: { "Content-Type": "application/json" },
method: "POST",
body: ""
}
)
.then(data => data.json())
.then((json) => {
alert(JSON.stringify(json));
document.getElementById("form").reset();
});
return false;
}
This also resets your form after a successful api call is made.

Ajax Request not working after production build of gatsby js

I have a simple form setup on my static gatsbyJS site (using formspree.io). Now I implemented a simple AJAX request instead of redirecting the user to another page.
While in development mode it all works perfectly fine. Once I build and serve the site though, it somehow falls back to redirecting after submitting the form. I just can't figure out whats wrong here, any help would be much appreciated.
Here is my form:
<form id='myform' action="http://formspree.io/testmail#gmail.com" method="POST">
<div className="formgroup">
<input id='name' type="text" name="name" placeholder='Name'/>
<input id='email' type="email" name="email" placeholder='Email'/>
</div>
<div className="formfield">
<textarea id='message' name="message" rows='6' placeholder='Message'/>
</div>
<div className="formfield">
<input id='send-button' type="submit" value="Send"/>
</div>
</form>
and here is my Javascript:
if (typeof window !== `undefined`) {
document.addEventListener('DOMContentLoaded',function(){
var contactForm = document.querySelector('#myform'),
inputName = contactForm.querySelector('[name="name"]'),
inputEmail = contactForm.querySelector('[name="email"]'),
inputMessage = contactForm.querySelector('[name="message"]'),
sendButton = contactForm.querySelector('#send-button');
sendButton.addEventListener('click', function(event){
event.preventDefault(); // prevent the form to do the post.
sendButton.value = 'Sending..';
var xhr = new XMLHttpRequest();
xhr.open('POST', '//formspree.io/testmail#gmail.com', true);
xhr.setRequestHeader("Accept", "application/json");
xhr.setRequestHeader("Content-Type", "application/x-www-form-urlencoded");
xhr.onloadend = function (res) {
if (res.target.status === 200){
sendButton.value = 'Message sent! I will be in touch soon.';
contactForm.reset();
} else {
sendButton.value = 'Error!';
}
}
xhr.send("name=" + inputName.value + "email=" + inputEmail.value + "message=" + inputMessage.value);
});
});
}
After being pointed into the right direction I got it to work..
I used the snippet from https://www.snip2code.com/Snippet/1613019/formspree-with-fetch/ and modified it slightly to change the button text while submitting. It works perfectly on a build environment of a gatsbyjs site:
if (typeof window !== `undefined`) {
window.onload=function(){
const sendButton = document.getElementById('send-button')
const formDataToJson = formData => {
const entries = formData.entries();
const dataObj = Array.from(entries).reduce( (data, [key, value]) => {
data[key] = value;
if (key === 'email') {
data._replyTo = value;
}
return data;
}, {});
return JSON.stringify(dataObj);
};
const postToFormspree = formData => fetch(`https://formspree.io/youremail#gmail.com`, {
method: 'POST',
body: formDataToJson(formData),
headers: {
'Content-Type': 'application/json'
}
}).then(r => r.json());
document.getElementById('myform').addEventListener('submit', function (e) {
e.preventDefault();
sendButton.value = 'Sending..';
const formData = new FormData(this);
postToFormspree(formData).then(response => {
sendButton.value = 'Message sent!';
myform.reset();
});
});
}
}

Angularjs canceled a post and refresh the page without sense

I have an issue that appears recently (I don't know what was changed)when trying to upload a file to my server.
With all other GET and POST the site is working ok, but the issue is when I need to upload a file (for which I have an specific function).
My site is built with angularjs and Java Spring as backend.
Here you have the function that is use in the factory to upload a file:
var SaveMethod = function(params, callback){
var result = $q.defer();
var form = new FormData();
var xhr = new XMLHttpRequest;
// Additional POST variables required by the API script
form.append("file", params.files);
xhr.upload.onprogress = callback;
xhr.open('POST', SessionService.apiUrl + '/video/save');
xhr.setRequestHeader("Authorization", 'Bearer ' + SessionService.getToken());
xhr.timeout = result.promise;
xhr.onload = function(e) {
if (xhr.status == 200) {
result.resolve(e.target.response);
}
else {
result.reject(xhr.statusText);
}
};
xhr.send(form);
return result.promise;
};
And this is the controller:
$scope.upload = function(item) {
$scope.values.videosubmitted = true;
$scope.values.object.name = item.name.substr(0, item.name.lastIndexOf('.'));
$scope.values.uploading = true;
var params = {
files: item
};
VideoFactory.Save(params, callback).then(function(response){
response = JSON.parse(response);
$scope.values.uploading = false;
if (response.success) {
$scope.values.object.images = response.data.images;
$scope.values.object.code = response.data.code;
$scope.values.object.source = response.data.source;
$scope.values.object.preview = response.data.preview;
}
else
{
$scope.values.error = true;
$scope.values.errorMessage = response.code;
}
}, function(response){
if (response == null) {
$scope.values.error = true;
$scope.values.errorMessage = "ERROR__SERVER_NON_WORKING";
}
else
{
$scope.values.error = true;
$scope.values.errorMessage = response.code;
}
$scope.values.uploading = false;
});
}
And the view (just in case)
<div class="row" ng-show="!values.videosubmitted">
<div class="col-md-10 no-padding-right">
<div class="dropzone" id="dropbox" callback-fn="upload(video)" file-dropzone="[video/mp4, video/3gpp, video/quicktime, video/x-msvideo, video/x-ms-wmv]"
file="image" file-name="imageFileName" values-max-file-size="9000000000">
<span translate="MODULES.VIDEO.DROPVIDEO"></span>
</div>
</div>
<div class="col-md-2 upload-btn no-padding-left">
<label class="upload-search btn btn-primary no-padding">
<div>
<input type="file" onchange="angular.element(this).scope().upload(this.files[0])"/>
<i class="fa fa-upload"></i>
<span translate="COMMON.FILESEARCH"></span>
</div>
</label>
</div>
</div>
The thing is that after the file is sent to the server, it doesn't matter if I get a successful response from server or not, the page is reloaded and the request is canceled. In some cases, I get the successful response from the server but after that the page is reloaded, and in other cases the request is canceled and the page is refreshed.
I tried with the timeout but it doesn't work.
And this is how it looks like:
The issue was something related to CORS I guess..
The thing was that I was using two domains for the web development, localhost for regular use, and an specific domain for being recognize in social media pages to allow the login buttons.
So I discover that when I was using localhsot everything works ok, but when using the other domain it was not.
It was so weird because the backend responded correctly to the request.

Submit Embedded Mailchimp Form with Javascript AJAX (not jQuery)

I have been trying to submit an embedded Mailchimp form with AJAX but without using jQuery. Clearly, I am not doing this properly, as I keep ending up on the "Come, Watson, come! The game is afoot." page :(
Any help with this would be greatly appreciate.
The form action has been altered to replace post?u= with post-json?u= and &c=? has been added to the end of the action string. Here is my js:
document.addEventListener('DOMContentLoaded', function() {
function formMailchimp() {
var elForm = document.getElementById('mc-embedded-subscribe-form'),
elInputName = document.getElementById('mce-NAME'),
elInputEmail = document.getElementById('mce-EMAIL'),
strFormAction = elForm.getAttribute('action');
elForm.addEventListener('submit', function(e) {
var request = new XMLHttpRequest();
request.open('GET', strFormAction, true);
request.setRequestHeader('Content-Type', 'application/json; charset=UTF-8');
request.onload = function() {
if (request.status >= 200 && request.status < 400) {
// Success!
var resp = JSON.parse(request.responseText);
request.send(resp);
} else {
console.log('We reached our target server, but it returned an error');
}
};
request.onerror = function() {
console.log('There was a connection error of some sort');
};
});
}
formMailchimp();
});
Also, I anticipate the inevitable "why don't you just use jQuery" comment. Without going into the specifics of this project, jQuery is not something I am able to introduce into the code. Sorry, but this HAS to be vanilla javascript. Compatibility is for very modern browsers only.
Thanks so much for any help you can provide!
A few days back I've had the exact same problem and as it turns out the MailChimp documentation on native JavaScript is pretty sparse. I can share with you my code I came up with. Hope you can build from here!
The simplified HTML form: I've got the from action from the MailChimp form builder and added "post-json"
<div id="newsletter">
<form action="NAME.us1.list-manage.com/subscribe/post-json?u=XXXXXX&id=XXXXXXX">
<input class="email" type="email" value="Enter your email" required />
<input class="submit" type="submit" value="Subscribe" />
</form>
</div>
The JavaScript: The only way to avoid the cross-origin problem is to create a script and append it to the header. The callback occurs then on the ā€œcā€ parameter. (Please note there is no email address validation on it yet)
function newsletterSubmitted(event) {
event.preventDefault();
this._form = this.querySelector("form");
this._action = this._form.getAttribute("action");
this._input = this._form.querySelector("input.email").value;
document.MC_callback = function(response) {
if(response.result == "success") {
// show success meassage
} else {
// show error message
}
}
// generate script
this._script = document.createElement("script");
this._script.type = "text/javascript";
this._script.src = this._action + "&c=document.MC_callback&EMAIL=" + this._input;
// append script to head
document.getElementsByTagName("head")[0].appendChild(this._script);
}
var newsletter = document.querySelector("#newsletter")
newsletter.addEventListener("submit", newsletterSubmitted);

Categories

Resources