localStorage onClick button display undefined values? - javascript

I am trying to display in localstorage the values I get from my api by clicking on a button.
But it seems that the value is not displayed, but the api call has been made, my value is undefined, so I have to click a second time on the button for my value to be displayed.
there is my code :
<template>
<div class="container">
<h1>SignIn</h1>
<div class="overlay-container">
<form>
<div class="form-group">
<input
type="text"
class="form-control"
placeholder="First name"
id="FirstName"
/>
</div>
<div class="form-group">
<input
type="text"
class="form-control"
placeholder="Last name"
id="Lastname"
/>
</div>
<div class="form-group">
<input
type="email"
class="form-control"
placeholder="Email"
id="exampleInputEmail1"
aria-describedby="emailHelp"
/>
</div>
<div class="form-group">
<input
type="password"
placeholder="Password"
class="form-control"
id="exampleInputPassword1"
/>
</div>
<button #click="signIn" type="button" class="btn btn-primary">Sign In</button>
</form>
</div>
</div>
</template>
<script>
import axios from 'axios'
import VueAxios from 'vue-axios'
export default {
name: "Signin",
data(){
return {
userName:'',
userid:''
}
},
methods:{
signIn(){
axios.get(`http://localhost:4000/api/users/2`)
.then(Response => this.userid = Response.data.data.id);
axios.get(`http://localhost:4000/api/users/2`)
.then(Response => this.UserName = Response.data.data.fname);
localStorage.userid = this.userid;
localStorage.UserName = this.UserName;
}
}
};
</script>
some screenshot : First CLick | Second Click
Do you have any idea of whats the problem ?

This should work. https://www.w3schools.com/jsref/met_storage_setitem.asp
async signIn() {
await axios.get(`http://localhost:4000/api/users/2`)
.then(Response => this.userid = Response.data.data.id);
await axios.get(`http://localhost:4000/api/users/2`)
.then(Response => this.UserName = Response.data.data.fname);
localStorage.setItem('userid', this.userid);
localStorage.setItem('UserName', this.UserName);
}

The values from your api calls are only available inside the .then function. So what's happening is, you're setting the keys/values on localStorage directly, before the promise returned from axios.get has resolved.
The reason you are only seeing the values reflected in localStorage after the second click has to do with promises and the order of execution. The first time you click the button, you're sending two GET requests, and then immediately updating localStorage with this.userid / this.UserName, both of which are still empty strings. After that function finished executing, the promise from axios.get resolves, and the values of this.userid / this.UserName are updated by the .then function. The second time you click the button, the localStorage values are updated with the values of this.userid / this.UserName which were previously set.
Also, bear in mind, you should use localStorage.setItem('key', 'value') instead of localStorage.key = 'value'.
The bottom line is, you should move the code that stores key/value pairs in localStorage inside of the .then.

You are not waiting for the ajax (xhr) to complete before saving the values in local storage. .then is the function called after the xhr is complete, so your code to save the values in local storage should be inside .then
axios.get(`http://localhost:4000/api/users/2`)
.then(function(Response) {
this.userid = Response.data.data.id
localStorage.setItem('userid', this.userid);
this.UserName = Response.data.data.fname
localStorage.setItem('UserName', this.UserName);
});
Because both your API calls are to the same endpoint, I have also combined them into one.
Now about your button click:
If you need to show data on click then you should only allow click after the data is received from the API call. To do this you can disable the button until .then is complete. And then re-enable it.
//**button is disabled when page loaded**
axios.get(`http://localhost:4000/api/users/2`)
.then(function(Response) {
this.userid = Response.data.data.id
localStorage.setItem('userid', this.userid);
this.UserName = Response.data.data.fname
localStorage.setItem('UserName', this.UserName);
//**enable button here**
});
Now the fact that you are making the call to your API even when data is stored in localstorage:
I am assuming that you are storing the data in localstorage so that you don't have to make another call to fetch it again.
But currently, your code always makes the API call even when the data is aready presnt in local storage.
You can fix it like this:
//**button is disabled when page loaded**
methods:{
signIn(){
var uId = localStorage.getItem('userid');
var uName = localStorage.getItem('UserName');
if(uId && uName) {
//**enable button here**
}
}
getData() {
axios.get(`http://localhost:4000/api/users/2`)
.then(function(Response) {
this.userid = Response.data.data.id
localStorage.setItem('userid', this.userid);
this.UserName = Response.data.data.fname
localStorage.setItem('UserName', this.UserName);
//**enable button here**
});
}
}
Call getData when your page loads up and then enable the button. So, when the button is clicked the data, is available!

1.) Try onclick instead of #click.
2.) Log to the Console the data you received from localhost:4000

Related

SvelteKit: cookies.set() In Form Action Not Working

I am trying to implement JWT-based user sessions with SvelteKit, and have mostly been following the explanation for form actions given on their website: https://kit.svelte.dev/docs/form-actions
+page.svelte
<form method="POST" action="?/signIn">
<input type="text" name="name" />
<input type="password" name="password" />
<button type="submit">Submit</button>
</form>
+page.server.svelte
import { fail, redirect } from "#sveltejs/kit";
import { signIn } from "$lib/server/database";
export const actions = {
signIn: async ({ cookies, request }) => {
const data = await request.formData();
const name = data.get("name");
const password = data.get("password");
if (!name || !password) {
return fail(400);
}
try {
cookies.set("jwt", await signIn(name, password));
} catch (error) {
return fail(400);
}
throw redirect(303, "/");
},
};
I have tested my signIn method which I import and use here, and it does return a token when called with the correct credentials. So far, so good. However, I noticed that I don't see any cookies in my developer tools. It seems like the cookies.set() call simply does nothing. I'd like to set the returned JWT as a cookie so that I can authenticate my users, so what am I doing wrong?
In case anybody else has this problem: While the cookie was set as it was supposed to when using Chrome, it wasn't in Safari. I solved this by setting the secure option to false, even though the SvelteKit docs state that this is done automatically on localhost.

How to get object ID in array of object using axios GET method?

I am a coding boot camp student and currently learning the axios method.
Using the axios.get function, I would like to be able to dynamically pull by the object ID using forms. This is my my current JS code, at the moment it is pulling all the array of objects from the API.
This is the snip-it of the array of objects from the API.
enter image description here
The HTML form where the object id is to be entered is.
<form name = "axiosget">
<input type ="text" id ="id" placeholder="Get Id"/>
<button>Submit</button>
</form>
And this is my axios.get code with the api "https://api.sample.io/todo"
const axiosGet =document.axiosget;
axiosGet.addEventListener("submit", function(event){
event.preventDefault()
const axiosGetId = {
id: axiosGet.id.value
}
axios.get("https://api.sample.io/todo", axiosGetId)
.then((response) => console.log(response.data))
.catch((error) => console.log(error));
})
My POST works with suing this method. This is the HTML forms for the POST
<form name = "newpost">
<input name ="title" placeholder="Title"/>
<input name ="description" placeholder="Description"/>
<input name="imgUrl" placeholder="Image Url"/>
<button>Submit</button>
</form>
and this is the js code
const newPost =document.newpost;
newPost.addEventListener("submit", function(event){
event.preventDefault()
const newPostItem = {
title: newPost.title.value,
description: newPost.description.value,
imgUrl: newPost.imgUrl.value,
};
axios.post("https://api.sample.io/todo", newPostItem)
.then((response) => console.log(response.data))
.catch((error) => console.log(error));
});
On a REST API you should simply GET your "number 1" post with a simple /todo/1 route, so you can do a
const axiosGetId = {
id: axiosGet.id.value
}
axios.get(`https://api.sample.io/todo/${axiosGetId}`)
.then((response) => console.log(response.data))
.catch((error) => console.log(error));
or concatene the id at the end of the route "https://api.sample.io/todo/" + axiosGetId
or pass it as a get value to the server with "https://api.sample.io/todo?id=1"
the difference with your POST method is that you don't send the ID when you save your resource, because the server does it for you and decides which ID will be your new todo
Check endpoint api, maybe you can add query parametr in request like this?
axios.get("https://api.sample.io/todo/123")
or
axios.get("https://api.sample.io/todo?id=123")
or
axios.get("https://api.sample.io/todo?_id=123")

Why is .then not working after fetching info from a form?

My javascript function (submitEmail) should get the user's input and post it to /emails, convert the inputs to json and then log it into the console. I have console.log after each step and it does not get past fetching the inputs, so it tells me that that step was done but then I get the error: Uncaught and I don't know how to fix it.
This means that the .then in my function is not working and I don't know why. I am new to javascript so I'm not fully sure of how it works.
How do I fix this?
js:
document.addEventListener('DOMContentLoaded', function () {
...
// Submit form
document.querySelector('#compose-form').onsubmit = submitEmail;
});
function submitEmail() {
console.log('sent') // this is shown on the console
fetch('/emails', {
method: 'POST',
body: JSON.stringify({
recipients: document.querySelectorAll('#compose-recipients'), // this gets all the recipients
subject: document.querySelector('#compose-subject'), // this gets the subject
body: document.querySelector('#compose-body') // gets the body
})
})
console.log('fetched') // this is shown on the console
.then(response => response.json()) // this is where the error occurs
console.log('converted') // this isn't shown on the console
.then(result => {
// Print result
console.log(result);
});
console.log('results shown') // not shown
.catch(error => {
console.log('Error:', error);
});
load_mailbox('sent')
console.log('sent') // not shown
return false
};
html:
<form id="compose-form">
<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" class="btn btn-primary" id="submit-new" name="btnSubmit" />
</form>
it seems like the .then() methods actually tries to run on console.log() and because console.log() does not return a promise, you get an error
console.log('fetched').then(response => response.json())
you could do the log inside of the .then() callback instead, like this
fetch('https://example.com').then((response) => {
console.log('fetched);
return response.json();
})
You cannot put a console.log in between your promise and the then method.
fetch returns a promise
fetch('your endpoint') // this returns a promise
.then(yourCallBack) // this calls the then method of the promise
but your code
fetch('your endpoint') // this returns a promise
console.log('your message') // this returns undefined
.then(yourCallBack) // there is no then method on undefined
The promise is not assigned to anything and console.log returns undefined. undefined does not have a then method.

Email.js Works Locally, But not Once Deployed With React

I have set up Email.js to make a contact page for a website built with Next.js. It works completely fine when run locally, but does not work when hosted. The form does not even reset when the submit button is clicked. I do this in the sendEmail function. The error handler does not trigger either in the .then block. I get this error in the browser console:
Uncaught The user ID is required. Visit https://dashboard.emailjs.com/admin/integration
Here is how I send the emails:
export default function Book(props) {
const form = useRef();
const [sentMessage, setSentMessage] = useState();
const sendEmail = (e) => {
e.preventDefault();
emailjs
.sendForm(
props.SERVICE_ID,
props.EMAIL_TEMPLATE_ID,
form.current,
props.USER_ID
)
.then(
function (response) {
setSentMessage("Message sent successfully!");
},
function (error) {
setSentMessage("Message failed please email directly.");
}
);
document.getElementById("form").reset();
};
return (
<div className={styles.container}>
<div className={styles.formContainer}>
<form
className={styles.form}
ref={form}
onSubmit={sendEmail}
id="form"
>
<h3>Name (required):</h3>
<input type="text" required={true} name="user_name"></input>
<h3>Email (required):</h3>
<input type="email" required={true} name="user_email"></input>
<h3>Phone number (required):</h3>
<input type="number" required={true} name="phone_number"></input>
<h3>Message (optional):</h3>
<textarea name="message"></textarea>
<button type="submit" value="Send">
Submit
</button>
{sentMessage ? <p>{sentMessage}</p> : <p></p>}
</form>
</div>
</div>
);
}
export async function getServerSideProps() {
return {
props: {
USER_ID: process.env.USER_ID,
EMAIL_TEMPLATE_ID: process.env.EMAIL_TEMPLATE_ID,
SERVICE_ID: process.env.SERVICE_ID,
},
};
}
I have a .env.local file with the template id, user id and service id that all work fine locally. I use next-env and dotenv-load in the next.config.js file like so:
dotenvLoad();
const withNextEnv = nextEnv();
module.exports = withNextEnv({
reactStrictMode: true,
webpack(config) {
config.module.rules.push({
test: /\.svg$/i,
issuer: /\.[jt]sx?$/,
use: ["#svgr/webpack"],
});
return config;
},
});
I saw some problems online that people had with Gmail and remote email servers, so I switched the account to have no 2 factor authentication and use less secure apps as well. That had no effect.
All you need to do is set up the environment variables in the next.js dashboard then rebuild the site so they take effect.

Input undefined when sending post request to the nodejs api using react and axios

I'm trying to make a post request to an API that I created with mysql and node js using react and axios. But when I input in the data the response i get is 'undefined'.
When I put the data with postman, it works. I tried to log the data that I sent with my browser and I saw them.
So I think that maybe the structure
When i console.log the data in the browser, I can figure out those data
adapter: ƒ xhrAdapter(config)
data: "{"etudiants":{"name":"Fenohasina
Andrainiony","lastname":"fenohasina","birthdate":"12-12-12"}
So i think that maybe, the structure of the data I sent is different to the structure I can receive on my API because on my API: it is just
{"name":"Fenohasina
Andrainiony","lastname":"fenohasina","birthdate":"12-12-12"}
Is this the problem?
This is the api code:
app.post('/etudiants/add', (req, res)=>{
const {name,
lastname,
birthdate,
} = req.query;
const queryInsert =`insert into etudiants (name, lastname, birthdate) values('${name}', '${lastname}', '${birthdate}')`
connection.query(queryInsert, (err, rows, fields)=>{
if(err) {
throw err
}
res.json(rows);
res.end()
})
}
}`
And the React Code:
export default class PersonList extends React.Component {
state = {
name:'',
lastname:'',
birthdate:'',
}
handleSubmit = event => {
event.preventDefault();
const etudiants = {
name: this.state.name,
lastname:this.state.lastname,
birthdate:this.state.birthdate,
};
axios.post('http://localhost:8080/etudiants/add', {etudiants})
.then(res=>{
console.log(res);
console.log(res.data)
})
}
handleName = event => {
this.setState({
name: event.target.value
})}
handleLastname = event => {
this.setState({
lastname: event.target.value,
})}
handleBirthdate = event => {
this.setState({
birthdate: event.target.value
})}
render() {
return (
<div className='App'>
<form onSubmit={this.handleSubmit}>
<label>
Person Name:
<input type="text" name="name" id='name'value={this.state.name} onChange={this.handleName} />
</label>
<label>
Person Lastname:
<input type="text" name="lastname" id='lastname'value={this.state.lastname} onChange={this.handleLastname} />
</label>
<label>
Person birthdate:
<input type="text" name="genre" id='birthdate'value={this.state.birthdate} onChange={this.handleBirthdate} />
</label>
<button type="submit">Add</button>
</form>
</div>
)
Thank you in advance!
Yes the problem is with the data you send
It should be
axios.post('http://localhost:8080/etudiants/add', {...etudiants})
(note the spread operator ... so that your etudiants constant is expanded in the object you send. Otherwise it just creates a property named etudiants which contains the contents of your constant)
Your code uses the short notation introduced in ES6
see https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/Object_initializer#Property_definitions
additionally you could re-use a single method for your input handling since they all do the same thing. So handleName, handleLastname and handleBirthdate could be replaced by just
handleInput = event => {
const {name, value} = event.target;
this.setState({
[name]: value
});
}
finally i think
<input type="text" name="genre" id='birthdate'
should really be
<input type="text" name="birthdate" id='birthdate'
I think the problem is how you are extracting the request data in the backend. In the react code, this is how you are making the request to the server:
axios.post('http://localhost:8080/etudiants/add', {etudiants})
The default behavior of Axios, when used like this, is to JSON serialize the request data(i.e {etudiants}) Refrence.
In order to receive and use this data in the backend, you need to parse the JSON request body, if you are using a body-parser middleware like this one, that should already be done for you. Then, you can extract the request body like this:
const {
name,
lastname,
birthdate,
} = req.body.etudiants;
Note how I replaced req.query with req.body and the addition of etudiants.

Categories