Why do I get empty string from req.body.newItem? - express

Github repo: https://github.com/tomkovladko/goormProblem
I posted my Todolist App(from Colt's lecture on Udemy) on Goorm and everything works just fine except one thing.
I tried to make a POST method so that if you press enter it goes to /addItem and creates and add new <li> to the body.
that unfortunately doesn't work and i just get this:
{ newItem: '' }
I compared it to PostRequestDemo that Colt did and it's almost the same code, here:
Mine
app.post("/newItem", function(req,res){
var newItem = req.body.newItem
console.log(newItem) #here is where i get the empty string... it should print something i inputed to the form (for example "banana")
res.redirect("/")
})
---------------------
<form action="/newItem" method="POST">
<input type="text" name="newItem" placeholder="Add New Todo">
</form>
Colt's
app.post("/addFriend", function(req, res){
var newFriend = req.body.newFriend
friends.push(newFriend)
res.redirect("friends")
})
---------------------
<form method="POST" action="/addFriend">
<input type="text" name="newFriend" placeholder="Name" required>
<button>Submit</button>
</form>
if you need more code just let me know bum I'm very very confused because I just started using goorm and express and all of that

Related

axios.post automatically splice url with my params

I want to implement an api with vue and axios in my front-end:
methods:{
startSpider:function(event){
alert("spider is ready to run!");
let data = {'searchKey':this.searchKey,
'category':this.category,
'num':this.num};
axios.post("{% url 'main:getCommodityInfo'%}",
data,
{headers:{'X-CSRFToken': this.getCookie('csrftoken')}})
.then(response=>{
console.log(response.data)
})
.catch(error=>{
console.log(error);
alert("connection has error")
})
},
When I call this function, I expect to get data from the back-end and stay at the inital url. It does receive data but the url quickly changed.
After some exploration, I find the browser implement two request! First, POST, and next GET:
Using 'searchKey':'switch', 'category':'electronic','num':60 as an example.
and My browser url subsequently changes to
Why it happens? I have just used POST not GET. The axios post seems to automatically splice inital url with the params. I have tried a lot of ways but failed. Even I have writed a small demo with the similiar structure like this to test, but the demo runs well! What happened? Help me please...
Updated I: Give my server behavior(django-view) and my router related is path('getCommodityInfo/',views.getCommodityInfo, name = 'getCommodityInfo')
def getCommodityInfo(request):
print(request.body)
return JsonResponse({"data":True}, safe=False)
Updated II: Give my front-end form:
<form>
<label for="searchKey">KeyWords</label>
<input v-model="searchKey" placeholder="Input Search Key" type="string" class="form-control" id="searchKey" name="searchKey">
<label for="category">Commodity Category</label>
<select v-model="selected" id="category" name="category">
<option v-for="option in options" v-bind:value="option.value">
${option.text}
</option>
</select>
<br>
<label for="num">Amount</label>
<input v-model="num" placeholder="Input amount needed" type="string" class="form-control" id="num" name="num" >
<button v-on:click="startSpider" class="btn btn-default">Submit</button>
<p>KeyWords : ${ searchKey }</p>
<p>Category : ${ selected }</p>
<p>Amount: ${ num }</p>
</form>
The bug happened because of not setting button type.
We could check this:
The missing value default is the Submit Button state.
And in the front-end form there is no type for the button, so the button type will be submmit button. When click on the button, it will automatically send a get request.
Modify the button like this:
<button v-on:click="startSpider" class="btn btn-default" type='button'>Submit</button>

Getting form data on submit?

When my form is submitted I wish to get an input value:
<input type="text" id="name">
I know I can use form input bindings to update the values to a variable, but how can I just do this on submit. I currently have:
<form v-on:submit.prevent="getFormValues">
But how can I get the value inside of the getFormValues method?
Also, side question, is there any benefit to doing it on submit rather than updating variable when user enters the data via binding?
The form submit action emits a submit event, which provides you with the event target, among other things.
The submit event's target is an HTMLFormElement, which has an elements property. See this MDN link for how to iterate over, or access specific elements by name or index.
If you add a name property to your input, you can access the field like this in your form submit handler:
<form #submit.prevent="getFormValues">
<input type="text" name="name">
</form>
new Vue({
el: '#app',
data: {
name: ''
},
methods: {
getFormValues (submitEvent) {
this.name = submitEvent.target.elements.name.value
}
}
}
As to why you'd want to do this: HTML forms already provide helpful logic like disabling the submit action when a form is not valid, which I prefer not to re-implement in Javascript. So, if I find myself generating a list of items that require a small amount of input before performing an action (like selecting the number of items you'd like to add to a cart), I can put a form in each item, use the native form validation, and then grab the value off of the target form coming in from the submit action.
You should use model binding, especially here as mentioned by Schlangguru in his response.
However, there are other techniques that you can use, like normal Javascript or references. But I really don't see why you would want to do that instead of model binding, it makes no sense to me:
<div id="app">
<form>
<input type="text" ref="my_input">
<button #click.prevent="getFormValues()">Get values</button>
</form>
Output: {{ output }}
</div>
As you see, I put ref="my_input" to get the input DOM element:
new Vue({
el: '#app',
data: {
output: ''
},
methods: {
getFormValues () {
this.output = this.$refs.my_input.value
}
}
})
I made a small jsFiddle if you want to try it out: https://jsfiddle.net/sh70oe4n/
But once again, my response is far from something you could call "good practice"
You have to define a model for your input.
<input type="text" id="name" v-model="name">
Then you you can access the value with
this.name inside your getFormValues method.
This is at least how they do it in the official TodoMVC example: https://v2.vuejs.org/v2/examples/todomvc.html (See v-model="newTodo" in HTML and addTodo() in JS)
Please see below for sample solution, I combined the use of v-model and "submitEvent" i.e. <input type="submit" value="Submit">. Used submitEvent to benefit from the built in form validation.
<!DOCTYPE html>
<html>
<head>
<script src="https://unpkg.com/vue"></script>
</head>
<body>
<div id="app">
<form #submit.prevent="getFormValues">
<div class="form-group">
<input type="email" class="form-control form-control-user"
v-model="exampleInputEmail"
placeholder="Enter Email Address...">
</div>
<div class="form-group">
<input type="password" class="form-control"
v-model="exampleInputPassword" placeholder="Password"> </div>
<input type="submit" value="Submit">
</form>
</div>
<script>
const vm = new Vue({
el: '#app',
methods: {
getFormValues (submitEvent) {
alert("Email: "+this.exampleInputEmail+" "+"Password: "+this.exampleInputPassword);
}
}
});
</script>
</body>
</html>
The other answers suggest assembling your json POST body from input or model values, one by one. This is fine, but you also have the option of grabbing the whole FormData of your form and whopping it off to the server in one hit. The following working example uses Vue 3 with Axios, typescript, the composition API and setup, but the same trick will work anywhere.
I like this method because there's less handling. If you're old skool, you can specify the endpoint and the encoding type directly on the form tag.
You'll note that we grab the form from the submit event, so there's no ref, and no document.getElementById(), the horror.
I've left the console.log() there to show that you need the spread operator to see what's inside your FormData before you send it.
<template>
<form #submit.prevent="formOnSubmit">
<input type="file" name="aGrid" />
<input type="text" name="aMessage" />
<input type="submit" />
</form>
</template>
<script setup lang="ts">
import axiosClient from '../../stores/http-common';
const formOnSubmit = (event: SubmitEvent) => {
const formData = new FormData(event.target as HTMLFormElement);
console.log({...formData});
axiosClient.post(`api/my-endpoint`, formData, {
headers: {
"Content-Type": "multipart/form-data",
}
})
}
</script>

How to login to an external website with Google Apps Scripts?

I'm trying to login to a website so that I can pull back data to a Google docs spreadsheet. I've read various posts here, but I can't work out how to identify the data I need to pass.
The login page of the site has a form with the following fields.
<form action="https://fantasyfootball.telegraph.co.uk/premierleague/log-in/" method="post" id='reg-form'>
<fieldset class='login'>
<div class="required">
<label for="email">Email:</label>
<input type="text" name="email" id="email" class="input-text" size="10" maxlength="50" value="my.name#address.com" />
</div>
<div class="required">
<label for="pass">Password:</label>
<input type="password" name="pass" id="pass" class="input-password" size="10" maxlength="15" value="some-password" />
</div>
</fieldset>
<div id="remember-me-container">
<input type="checkbox" checked="checked" id="remember-me" name="remember-me" value="remember-me" />
<label for="remember-me" id="remember-lbl">Remember me</label>
</div>
<input type="submit" id="submit-btn" value="Login" name='Submit' class='btn'/>
</form>
I've tried the following script, but the sessionDetails always comes back as "Undefined."
// Returns the html of the page.
function sGetPage (sUrl) {
var url = "https://fantasyfootball.telegraph.co.uk/premierleague/log-in/";
// logging in, following http://stackoverflow.com/questions/21621019/google-apps-script-login-to-website-with-http-request
var payload =
{
"email" : "ian.shaw#iee.org",
"pass" : "asdf123",
"submit-btn": "Login",
"remember-me" : "remember-me"
};
var options =
{
"method" : "post",
"payload" : payload,
"followRedirects" : false
};
var login = UrlFetchApp.fetch( url, options);
var sessionDetails = login.getAllHeaders()['Set-Cookie'];
Logger.log(sessionDetails);
var response = UrlFetchApp.fetch ("https://fantasyfootball.telegraph.co.uk/premierleague/leagues/view/8000912/4015677/", {"headers" : {"Cookie" : sessionDetails} });
var sHtml = response.getContentText();
Logger.log(sHtml);
}
Any advice would be appreciated.
I haven't ever been able to send sessionDetails back to the site as-is. I've been using RegEx to extract the relevant parts of sessionDetails and create a new cookie string, and send that back to the site. To find out what parts of the cookie are relevant, use your browser's network log (in the developer tools) to examine what your browser posts for the cookie, and compare that string to sessionDetails. I posted an example here.
var login = UrlFetchApp.fetch(url, options);
var sessionDetails = login.getAllHeaders()['Set-Cookie'];
Logger.log(sessionDetails);
var cookie = sessionDetails.match(/Asp\.NetSessionId=[A-Z0-9]+;/)[0]; //modify this RegEx as needed
var response = UrlFetchApp.fetch(
"https://example.com",
{"headers" : {"Cookie" : cookie} }
);

how to show dojo validation error tool tip?

Question:--
I am using following HTML code showing error message using tool tip whenever length of Textbook equal to zero,
but i couldn't set my defined message inside tool tip.
<body class="claro">
<form action="">
Enter Name:--
<input type="text" name="firstname" data-dojo-props="" data-dojo-type="dijit.form.TextBox"
trim="true" id="firstname" propercase="true">
<button id="button4" data-dojo-type="dijit.form.Button" type="button">Submit
<script type="dojo/method" event="onClick" args="newValue">
alert("Value selected is: "+newValue);
var firstNameId=dijit.byId("firstname").value;
alert('firstNameId.length:----'+firstNameId.length);
if(firstNameId.length==0)
{
var textBox = dijit.byId("firstname");
dijit.showTooltip(
textBox.get("invalidMessage"),
textBox.domNode,
textBox.get("justMessage"),
!textBox.isLeftToRight()
);
}
else
{
alert('wrong');
);
}
<br>
Help me out....
It's been a while since you posted this question, but if you still need it, here's an answer.
Dijit/form/TextBox doesn't have a showTooltip method. To show a tooltip you can instead call something like:
var textBox = dijit.byId("firstname");
textBox.invalidMessage = "Whatever you want";
Tooltip.show(textBox.get("invalidMessage"),
textBox.domNode, textBox.get("tooltipPosition"),
!textBox.isLeftToRight());
Be sure to include dijit/Tooltip!

Html Form - route is wrong

I am using the FileUpload sample from the asp.net tutorials. When I build it as a stand alone, it works fine. However, whenever I try to add that functionality to a new MVC4 website, the routing is wrong. I'm probably not explaining this well, so here is the code:
[HttpPost]
public async Task<HttpResponseMessage> PostFile()
{
// Check if the request contains multipart/form-data.
if (!Request.Content.IsMimeMultipartContent())
{
throw new HttpResponseException(HttpStatusCode.UnsupportedMediaType);
}
string root = HttpContext.Current.Server.MapPath("~/App_Data");
var provider = new MultipartFormDataStreamProvider(root);
try
{
var sb = new StringBuilder(); // Holds the response body
// Read the form data and return an async task.
await Request.Content.ReadAsMultipartAsync(provider);
// This illustrates how to get the form data.
foreach(var key in provider.FormData.AllKeys)
{
var strings = provider.FormData.GetValues(key);
if (strings != null) foreach(var val in strings)
{
sb.Append(string.Format("{0}: {1}\n", key, val));
}
}
// This illustrates how to get the file names for uploaded files.
foreach(var file in provider.FileData)
{
var fileInfo = new FileInfo(file.LocalFileName);
sb.Append(string.Format("Uploaded file: {0} ({1} bytes)\n", fileInfo.Name, fileInfo.Length));
}
return new HttpResponseMessage
{
Content = new StringContent(sb.ToString())
};
}
catch (System.Exception e)
{
return Request.CreateErrorResponse(HttpStatusCode.InternalServerError, e);
}
}
Here is the page I'm using:
<div style="height:400px;">
<h3>File Upload</h3>
<form name="trip_search" method="post" enctype="multipart/form-data" action="api/upload">
<div>
<input type="radio" name="trip" value="round-trip"/>
Round-Trip
</div>
<div>
<input type="radio" name="trip" value="one-way"/>
One-Way
</div>
<div>
<input type="checkbox" name="options" value="nonstop" />
Only show non-stop flights
</div>
<div>
<input type="checkbox" name="options" value="airports" />
Compare nearby airports
</div>
<div>
<input type="checkbox" name="options" value="dates" />
My travel dates are flexible
</div>
<div>
<label for="seat">Seating Preference</label>
<select name="seat">
<option value="aisle">Aisle</option>
<option value="window">Window</option>
<option value="center">Center</option>
<option value="none">No Preference</option>
</select>
</div>
<div>
<input type="submit" value="Submit" />
</div>
</form>
When I directly navigate to localhost:13927api/upload I see a response from the web api method. I've got the DefaultApi route registered in my WebApiConfig.
But when I'm on the page localhost/Home/About and I click on the submit button, it attempts to go to localhost/Home/api/upload - which does not exist.
What am I missing?
EDIT
The suggestion by Mario fixed my issue. The action method on my form was not relative to the root.
action="api/upload" vs. action="/api/upload"
That fixes my problem.
A bit of elaboration on the issue:
When you are in the default path (say yoursite/Home/Index -> if that is your default), then the action="api/myaction" will work because the current path is still seen as the root of the website. However, once you actually navigate to a path (say yoursite/Home/About), the current path is now under "Home" and so my missing "/" naturally was relative to my current path rather than the root. This is why the samples work without the leading "/", because the view in question is the default view.
Added the answer, if that can help others too:
Your form action="api/upload" is not relative to the root. Try action="/api/upload" or use one of the helpers to specify the route.