How to use PATCH method in an html form to send data to a server?
I've already done this
Html
<form class="type-title" method="POST" id="alter">
<input type="hidden" name="_method" value="PATCH"/>
<input id="alter" type="text" name="alter"/>
<button onclick="alter_name();">update</button>
</form>
JS
function alter_name(){
fetch("http://127.0.0.1:3000/api/member", {
method: 'PATCH',
headers: {
'Content-type' :'application/json'
},
body: {
"name":alter_name.value.toString()
}
}),then((response) =>{
return response.json();
}).then((data) =>{
console.log(data);
})
}
but it still not work
The main issue is how you have addressed the input value. Your form's id: id="alter" is the same name as the input which is invalid, but in your script you are not referencing this field correctly at all, lets fix all this...
Firstly with the HTML form, do not post back as that might affect other workflows on the form. We do this by forcing the button to act as a simple standalone HTML Button instead of being the submit button for the form. Do this by setting the type attribute of the button to "button":
_I've also changed the Id of the form to be unique and removed the _method hidden input.
<form class="type-title" id="alter_form">
<input id="alter" type="text" name="alter"/>
<button onclick="alter_name();" type="button">update</button>
</form>
You were on the right track with using javascript and fetch() to send the data as your API is not likely to be setup to accept form-data if you are using PATCH as the method on a standard form submit.
The other fix is in the script itself, we need to deliberately stringify the object payload that we sent in the body, this way we can control or enforce the serialization instead of relying on javascript, we can also more easily inspect the contents when or if it goes wrong.
Notice how the field is referenced using the path formId.fieldId.value
The other issue you had was that your JSON object wasn't formed correctly, you had quotes around the property name, which would have resulted in quotes being escaped and encoded into the JSON string value, which we don't want.
Finally, I've specified the encoding in the Content-Type as it was required on my system to parse the content on the server side.
function alter_name(){
let content = {
Details: alter_form.alter.value.toString()
};
fetch("http://127.0.0.1:3000/api/member", {
method: 'PATCH',
headers: {
'Content-type': 'application/json; charset=UTF-8',
'Accept': 'application/json'
},
body: JSON.stringify(content)
}).then((response) => {
console.log('PATCH Response.status: ', response.status);
if(response.status !== 204)
return response.json();
else
return response.statusText;
}).then((data) => {
alert(data);
});
}
For a few bonus points, I've added some handling for a 204: No Content response from the server. Many PATCH implementations do not return content unless you explicitly request it with a Prefer HTML Header.
Related
I connected a database to node and am trying to create an HTML page to search the database. I would rather not use EJS. I think I have to use a POST request in the HTML AJAX and connect it with a POST request in node.
Here is what I'm thinking:
app.post("/cities/:city", function(req, res) {
db.hospitalinfo.findAll({
where: { city: req.params.city }
}).then(function (result) {
res.json(result);
console.log("res--->"+result);
console.log("req--->"+req.params.city);
});
});
Here's the HTML:
<form id="author-form" method="POST">
<select id ="dropDownId">
<option value="Opp" >Opp</option>
<option value="Boaz">Boaz</option>
</select>
<input class="SubmitButton" type="submit" id="click" style="font-size:20px;" />
</form>
Now here's where I'm stuck. I need to grab the value from the select statement:
var nameInput = $("#dropDownId :selected");
I don't know how to actually send nameInput to the URL so my post statement will work. I probably don't completely understand how these routes work. This is my first project by myself. I would like to grab the nameInput, send it to the server via AJAX, and search my database with it. Right now it's returning an empty object. Thank you for your help.
You need to make a Ajax call to node server. For that you need to stop the default submit of form.
event.preventDefault();
can be used to stop the normal flow of submitting the form.
Here is an example of ajax call
(document).ready(function() {
// process the form
$('form').submit(function(event) {
// get the form data
// there are many ways to get this data using jQuery (you can use the class or id also)
var formData = {
'name' : $('input[name=name]').val(),
'email' : $('input[name=email]').val(),
};
// process the form
$.ajax({
type: "GET", // define the type of HTTP verb we want to use (POST for our form)
url: "http://localhost:5000/example" // the url where we want to POST
data: formData,
dataType: 'json', // what type of data do we expect back from the server
success: function (data) {
console.log(data.result);
// perform required changes
},
error: function (err) {
console.log(err);
}
});
// stop the form from submitting the normal way and refreshing the page
event.preventDefault();
});
});
you can refer this site for more details making ajax calls
I have modified the code taken from there.
I have an mvc3 application which makes use of an ajaxsubmit to a controller action.
The <form> opening tag in my page appears like this:
<form action="/application/home/Save?Length=0" class="form-horizontal" data ajax="true" data-ajax-method="POST" data-ajax-mode="after" data-ajax update="#jsonResult" enctype="multipart/form-data" id="inputForm" method="post" role="form">
If i submit this form from within the network that the server is based, the post request will always work. But if i submit the form externally, on occasions i get this generic error:
403 Forbidden: You don't have permission to access /application/home/Save on this server.
The above error doesnt always occur. only in particular instances.
Upon analysing the request headers, The only difference i see is Content-length:
They have the following:
The only other difference that i think could be the cause of this issue is in one of the fields in the request payload.
Now one of the fields i pass to the server is in a special code that has tilders and carrot symbols. Here is an example:
------WebKitFormBoundaryvvviIpe8b82tAvOd
Content-Disposition: form-data; name="udfArray"
["1~d^testfield~d^R"]
Whenever the form submit fails, it happens to have the above form data. When it succeeds, the field is set to []
The trouble is, i dont understand why having the code set to ["1~d^testfield~d^R"] should be an issue if it works within the network.
If anyone could point me in the right direction for making this work externally that would be great.
Here is my submit code:
//options for submit action
var options = {
data: {
udfArray: ko.toJSON(self.TempArray()),
title: self.title(),
given_name: self.givenName(),
//... other fields
},
uploadProgress: function () {
},
dataType: "json",
success: function (result) {
//do something
}
};
$('#inputForm').ajaxForm();
$('#inputForm').unbind('submit').submit(function () {
$('#loadingDiv').show();
$(this).ajaxSubmit(options);
return false;
});
So I have a html5 form with input fields. Lets say the fields are first name, last name, phone, email, and address.
Now first, last, and address are required while phone and email are optional. I know that the backend has this configured properly. However on the html5 form it will not let me submit without phone or email otherwise it returns a 400 error.
If I remove the optional from the html5 form, it will let me submit it or I can put in a value=" " and will submit also. I can even tag the fields with CSS3 using :required and :optional and it will show appropriately but still won't let me submit.
Now I obviously can't just remove the optional from the html because some users may need those fields but I also don't want to send a default value of " " or "n/a" for users who don't need them. Am I just doing something wrong here or what? I don't get what is going on.
edit 2: This is a node.js api using Hapi.js with Joi validation, request, and couchdb.
edit: I know that 400 is a server error but if I post with a curl omitting the optional ones it goes through fine. It also goes through fine when I remove the optional ones from the html which is why it doesn't make sense. Here is the validation code server side for the api.
handler: function(req, res) {
request({
method: 'POST',
uri: 'https://127.0.0.1:6984/banned',
jar: cookieJar,
strictSSL: false,
json: {
firstn: req.payload.firstn,
lastn: req.payload.lastn,
licno: req.payload.licno,
phone: req.payload.phone,
email: req.payload.email,
address: req.payload.address,
description: req.payload.description
}
},
function(err, resp, body) {
if (err) { res(err) };
if (resp.statusCode === 401) {
res(resp.statusCode + ' Please log in.');
}
else if (resp.statusCode === 201) {
res(body);
}
});
},
validate: {
payload: {
firstn: Joi.string().required(),
lastn: Joi.string().required(),
licno: Joi.string().optional(),
phone: Joi.string().optional(),
email: Joi.string().optional(),
address: Joi.string().optional(),
description: Joi.string().required()
}
}
So a friend helped me figure it out. What is happening is that required or not the html form is sending with a value of "" if no data is put in. That is not " ", "null", "undefined" just "". This is not a valid value for the server so it throws the 400 error. The code that fixed it was by checking if the payload exists before validating and sending it through.
I've got to say I'm a little confused about how to handle request parameter using the new Play Framework 2. The data comes from different origins regarding how the request is made. So far, here's the possibilities :
1 - If you do a simple GET :
ctx().request().queryString()
2 - If you do a POST using an HTML Form :
The form :
<form method="post" action="/">
<input type="hidden" name="foo" value="bar" />
<input type="hidden" name="t" value="1" />
<input type="hidden" name="bool" value="true" />
<input type="submit" name="submit" value="Submit" />
</form>
The method :
public static Result test() {
ctx().request().queryString(); // {} ; As expected
ctx().request().body(); // contains data
ctx().request().body().asFormUrlEncoded(); // contains data
ctx().request().body().asJson(); // empty
return ok();
}
This seems normal.
Now if I add #BodyParser.Of(BodyParser.Json.class) (suppose I accept both Ajax POST and normal POST for fallback in Non-JS case) :
#BodyParser.Of(BodyParser.Json.class)
public static Result test() {
ctx().request().queryString(); // {} ; as Expected
ctx().request().body(); // contains data
ctx().request().body().asFormUrlEncoded(); // empty : Shouldn't this contains data since I posted them via a simple form ?!
ctx().request().body().asJson(); // empty
return ok();
}
And then, the hell hapened : How can I get the values of a simple form if none of them are filled (asJson, asFormUrlEncoded, etc) ?!
3 - If you do a POST via AJAX :
// Code in JS used :
$.ajax({
'url': '/',
'dataType': 'json',
'type': 'POST',
'data': {'foo': 'bar', 't': 1, 'bool': true}
});
Result :
public static Result test() {
ctx().request().queryString(); // {}
ctx().request().body(); // contains data
ctx().request().body().asFormUrlEncoded(); // contains data
ctx().request().body().asJson(); // empty
return ok();
}
With the #BodyParser.Of(BodyParser.Json.class) :
#BodyParser.Of(BodyParser.Json.class)
public static Result test() {
ctx().request().queryString(); // {}
ctx().request().body(); // contains data
ctx().request().body().asFormUrlEncoded(); // empty
ctx().request().body().asJson(); // empty : Shouldn't this contains data since I espect JSON ?!
return ok();
}
Here the inconsistencies is the asJson() method that should return the data since, according to the doc
Note: This way, a 400 HTTP response will be automatically returned for non JSON requests. (http://www.playframework.org/documentation/2.0/JavaJsonRequests)
What I'd like to know is what is the best decorator+method for a POST that would accept a simple post from HTML or an Ajax Request with POST?
I would recommend to use the Form classes provided by PlayFramework.
The Form will bind its values to the provided request data.
There are two different Form implementations:
DynamicForm: POST data is available through Map accessors methods
Form: the generic form of Form will map the POST data to an instance of an entity class [more information]
The form also provides some usefull features like automatic type conversion, validation, error reporting and so on.
a simple example with a dynamic form:
ajax request:
$.post("#routes.Application.movetodo()",
{ "id": 123, "destination": destination }, function(data)
{
// do something when request was successfull
});
Routes file:
GET / controllers.Application.index()
POST /movetodo controllers.Application.movetodo()
Controller implementation:
public static Result movetodo()
{
DynamicForm data = form().bindFromRequest(); // will read each parameter from post and provide their values through map accessor methods
// accessing a not defined parameter will result in null
String id = data.get("id");
String destination = data.get("destination");
return ok();
}
The reason that asJson() will be empty is that by default, $.ajax will send a request with a content type set to 'application/x-www-form-urlencoded; charset=UTF-8'. You need to set it to 'application/json; charset=utf-8':
$.ajax({
contentType: "application/json; charset=utf-8",
...
})
$("#frmCompose").submit(function () {
$(this).ajaxSubmit({
success: function (response) {
alert('success');
}
});
});
Controller code:
[HttpPost]
public ActionResult SendEmail(EmailMessageModel emailMessage)
{
try
{
// do something with the data
return Json(new StatusModel { error = false });
}
catch (Exception)
{
return Json(new StatusModel { error = true, message = "Could not send email" });
}
}
View Code:
<form id="frmCompose" method="post" action="SendEmail">
<button id="compose" class="btn-pencil">
Send</button>
<div class="fields-inline">
<div class="editor-label">
#Html.Label("To:")
</div>
#Html.TextBox("txtTo")
</div>
<div class="fields-inline">
<div class="editor-label">
#Html.Label("Subject:")
</div>
#Html.TextBox("txtSubject")
</div>
<div class="fields-inline">
<div class="editor-label">
#Html.Label("Body:")
</div>
#Html.TextArea("txtBody")
</div>
</form>
In my controller I return a JSon result with a text message.
Why does the view in FireFox want to download the json as a file download?
All I want to do is ensure I get a response within the success callback
Solution is to return false within the submit() call function for the form.
That way, the json result is consumed within the submit function and not passed to the browser for handling.
$("#frmCompose").submit(function () {
// submit data to server here....
return false;
});
According to the documentation:
Since it is not possible to upload
files using the browser's
XMLHttpRequest object, the Form Plugin
uses a hidden iframe element to help
with the task. This is a common
technique, but it has inherent
limitations. The iframe element is
used as the target of the form's
submit operation which means that the
server response is written to the
iframe. This is fine if the response
type is HTML or XML, but doesn't work
as well if the response type is script
or JSON, both of which often contain
characters that need to be repesented
using entity references when found in
HTML markup.
To account for the challenges of
script and JSON responses, the Form
Plugin allows these responses to be
embedded in a textarea element and it
is recommended that you do so for
these response types when used in
conjuction with file uploads.
This basically means that if you want to upload files using the jquery form plugin and your form contains file input fields the server needs to wrap the returned JSON into <textarea> tags.