VueJs3 sending data from one component to another - javascript

I am currently working on a VueJs3 Project. I already coded a login system, which works perfectly fine. I now want to have a div on the homepage, that tells the user with which account they are logged in.
"You are logged in as:" + username
I therefore, have to send the username from the login component to the home component. Can someone help me out here? I have tried out a lot of ways but none of them seem to work.
Btw. the components are all saved in the components folder
Here is my code:
home.vue
<div class="home">
<h1>You are logged in as: {{currentusername}}</h1>
<Maschinen/>
</div>
</template>
<script>
import Maschinen from '#/components/Maschinen.vue'
import axios from 'axios'
export default {
name: 'Home',
components: {
Maschinen
},
data() {
return {
currentusername: null,
}
},
async created() {
const response = await axios.get('http://localhost:8080/user/hetwinuser', {
headers: {
Authorization: 'Bearer ' + localStorage.getItem('token')
}
});
this.currentusername= (response.data.username);
}
}
</script>
login.vue:
<template>
<form #submit.prevent="handleSubmit">
<h1>Login</h1>
<!--username + pw input for login-->
<div class="form-group">
<label id="username">Username:</label>
<input id="usernameinput" type="text" class="form-control" v-model="username" placeholder="Username">
</div>
<div>
<label id="password">Password:</label>
<input id="passwordinput" type="password" class="form-control" v-model="password" placeholder="Password">
</div>
<!--enter buttons-->
<button class="enter">Enter</button>
<router-link to="/register" id="goToRegister" tag="button">Register</router-link>
</form>
</template>
<script>
import axios from 'axios';
export default {
name: "Login",
data: () => {
return {
username: '',
password: ''
}
},
methods: {
async handleSubmit() {//executed when enter button is pressed
const data = {
username: this.username,
password: this.password
};
axios.post('http://localhost:8080/authenticate', data) //post the username + pw and will receive the token in exchange
.then(
res => {
localStorage.setItem('token', res.data.jwt);
localStorage.setItem('currentusername', this.username);
//console.log(localStorage.getItem('token'));
}
).catch(
err => {
console.log(err)
}
);
}
},
}
</script>```

username and password
Define it under store -> state.js. Then where you want it
Use it as "this.$store.state.username"

Related

Do these two Axios and github url have a difference

<template>
<div class="ls-repo">
<div
class="row justify-content-between ls-pin-repo"
v-for="repo in repos"
:key="repo.id"
>
<div class="col-md-6">
<router-link :to="repo.html_url"
><h6>{{ repo.name }}</h6></router-link
>
<div class="row ls-r">
<div class="col mt-4">
<span>{{ repo.language }}</span>
</div>
</div>
</div>
<div class="col-md-6">
{{ repo.full_name }} <br />
{{ repo.visibility }}
</div>
</div>
</div>
</template>
<script>
import axios from "axios";
export default {
name: "Repositories",
data() {
return {
repos: null,
search: "",
};
},
methods: {
setData(data) {
this.repos = data;
console.log(this.repos.node_id);
},
searchData() {
axios
.get("https://api.github.com/repos/dimaswntech/" + this.search, {
headers: {
Authorization: "token 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",
},
})
.then((response) => {
this.setData(response.data);
console.log(response.data);
})
.catch((error) => console.log(error));
console.log(this.search);
},
},
mounted() {
axios
.get("https://api.github.com/users/dimaswntech/repos", {
headers: {
Authorization: "token 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",
},
})
.then((response) => {
this.setData(response.data);
console.log(this.repos);
})
.catch((error) => console.log(error));
},
};
</script>
<style></style>
Im sorry friends, let me ask something. I am use vue js and i will fetch data from api github. In my method with name "seachData()" and Mounted part, i use axios. But i don't know, i got an error if i fill the input tag like this
<input
class="form-control input-repo"
type="text"
v-model="search"
v-on:keyup.enter="searchData"
/>
And my error said. my code has variable with null value. i those code i did not fill the input tag. So i hope you guys can help me.

How to use Axios from backend to frontend

I'm using reactjs as my development tool and mongoDB as my backend database.
I have my backend react code as following:
const express = require("express");
const jwt = require("jsonwebtoken");
const bcrypt = require("bcrypt");
const { User, VerificationCode } = require("../models");
const { isLoggedIn, getLoggedInUserId, generateRefreshToken } = require("./middlewares");
const sendVerificationEMail = require("./bin/send_email").sendVerificationEmail;
require("dotenv").config();
const router = express.Router();
router.post("/register", async (req, res, next) => {
const { email, username, password, first_name, last_name } = req.body;
try {
// Check if the email is duplicating
let existingUser = await User.findOne({ where: { email } });
if (existingUser) {
return res.status(409).json({
success: false,
message: "User already exists.",
});
}
existingUser = await User.findOne({ where: { username } });
if (existingUser) {
return res.status(409).json({
success: false,
message: "Same nickname user exists.",
});
}
const hash = await bcrypt.hash(password, 12);
await User.create({
email,
username,
password: hash,
first_name,
last_name,
});
return res.status(200).json({
success: true,
message: "Signup successful.",
});
} catch (error) {
return res.json({
success: false,
message: "Signup failed.",
});
}
});
// Login
// Create token and return to user (httpOnly cookies)
router.post("/login", async (req, res, next) => {
const { email, password } = req.body;
// Make a inquiry of the user through email
try {
const user = await User.findOne({ where: { email }, raw: true });
if (!user) {
return res.status(401).json({
success: false,
message: "No member exists.",
});
}
// Check password
const isMatch = await bcrypt.compare(password, user.password);
if (isMatch) {
// If the password matches,create JWT payload
const payload = {
uid: user.id,
};
// JWT token create
const token = jwt.sign(payload, process.env.JWT_SECRET, { expiresIn: req.app.get("jwt_expiration") });
// New refresh token and create expiration for it
let refresh_token = generateRefreshToken(req, user.id);
let refresh_token_maxage = new Date() + req.app.get("jwt_refresh_expiration");
// Browswer httpOnly cookie setting
res.cookie("access_token", token, {
// secure: true,
httpOnly: true,
});
res.cookie("refresh_token", refresh_token, {
// secure: true,
httpOnly: true,
});
// Save the account id as key and save in Redis server
req.client.set(
user.id,
JSON.stringify({
refresh_token: refresh_token,
expires: refresh_token_maxage,
}),
req.client.print
);
return res.json({
success: true,
uid: user.id,
message: "Login Successful",
});
} else {
return res.status(401).json({
success: false,
message: "Password's don't match.",
});
}
} catch (error) {
console.error(error);
res.status(401).json({
success: false,
message: "Login Error",
});
}
});
module.exports = router;
And I have my Login frontend code as following: (Login.js)
import React, { Component } from "react";
import login from "../picture/login.png";
import Form from "react-bootstrap/Form";
import axios from "axios";
export default class SignUp extends Component {
render() {
return (
<div style = {{
backgroundColor:'#f7feff'
}}>
<div class="container h-100">
<div class="row h-100 justify-content-center align-items-center">
<form class="col-6">
<br/><br/><br/>
<h2>Login</h2>
<hr />
<div class="row h-100 justify-content-center align-items-center">
<img src = {login}
width = '550'
height = '200'
alt='Login2'/>
</div>
<Form.Group controlId="formBasicEmail">
<Form.Label>Email address</Form.Label>
<Form.Control type="email" placeholder="Enter email" />
<Form.Text className="text-muted">
We'll never share your email with anyone else.
</Form.Text>
</Form.Group>
<Form.Group controlId="formBasicPassword">
<Form.Label>Password</Form.Label>
<Form.Control type="password" placeholder="Enter password" />
</Form.Group>
<Form.Group controlId="formBasicCheckbox">
<Form.Check type="checkbox" label="Remember me" />
</Form.Group>
<button type="submit" className="btn btn-info btn-block">Submit</button>
<div className = "App-wrapper">
<p className="forgot-password text-right">
<a href="signup"to="/signup">
Sign Up | </a>
<a href="password"to="/pasword">
Find Password</a>
</p>
</div>
</form>
</div>
</div>
</div>
);
}
}
My Signup frontend code is:(Signup.js)
import React, { Component } from "react";
import Form from "react-bootstrap/Form";
import welcome from "../picture/welcome.png";
export default class SignUp extends Component {
render() {
return (
<div style = {{
backgroundColor:'#f7feff'
}}>
<div class="container h-100">
<div class="row h-100 justify-content-center align-items-center">
<form class="col-6">
<br/><br/><br/>
<h2>Sign Up</h2>
<hr />
<div class = "row h-100 justify-content-center align-items-center">
<img src = {welcome}
width = '550'
height = '200'
alt='signup'/>
</div>
<Form.Group controlId="formBasicEmail">
<Form.Label>*Email address</Form.Label>
<Form.Control type="email" placeholder="Enter email" />
</Form.Group>
<Form.Group controlId="formBasicUsername">
<Form.Label>*Username</Form.Label>
<Form.Control placeholder="Enter username" />
</Form.Group>
<Form.Group controlId="formBasicPassword">
<Form.Label>*Password</Form.Label>
<Form.Control type="password" placeholder="Enter password" />
</Form.Group>
<Form.Group controlId="formBasicFirstname">
<Form.Label>*Firstname</Form.Label>
<Form.Control placeholder="Enter firstname" />
</Form.Group>
<Form.Group controlId="formBasicLastname">
<Form.Label>*Lastname</Form.Label>
<Form.Control type placeholder="Enter lastname" />
</Form.Group>
<Form.Group controlId="formBasicTelephone">
<Form.Label>Telephone</Form.Label>
<Form.Control type="number"placeholder="Enter telephone number"/>
</Form.Group>
<Form.Text className="text-muted">
Fields that are marked with asterisk(*) are compulsory.
</Form.Text>
<button type="submit" className="btn btn-info btn-block">Sign Up</button>
<p className="forgot-password text-right">
Already registered? sign in?
</p>
</form>
</div>
</div>
</div>
);
}
}
I really don't know how to connect backend and frontend using axios. The login server url is localhost:8002/auth/login and for signup: localhost:8002/auth/signup
In your React component, you have to make a function that uses axios to call the backend, and then add that as a onClick handler to the submit button.
To make a request with axios you have to use the functions available on the axios module. In your case, this could look something like this:
function onSubmit() {
axios.post('localhost:8002/auth/login',
{username: username,
password: password });
}
Be aware that axios.post returns a promise, so you would have to await it/use .then to get the response from the backend. When you have the function, you can attach it to your login button like this:
<button type="submit" className="btn btn-info btn-block" onClick={onSubmit}>Submit</button>
EDIT: And the username and password values are of course the values that the user has entered via the input fields. You can store these in the state of the component.

Vue test login form

I created a login form with vuejs. I'm new with the vue framework and want to write a test for my api call.
This is the form:
<template>
<div>
<div class="col q-mb-md">
<div class="row">
<q-btn
#click="loginGoogle"
type="submit"
color="primary"
class="col"
name="login_google"
outline
size="lg"
label="Login with Google" />
</div>
</div>
<div class="col q-mb-md">
<div class="row">
<q-btn
type="submit"
color="primary"
class="col"
name="login_apple"
outline
size="lg"
label="Login with Apple ID" />
</div>
</div>
<form #submit.prevent="submitForm" class="q-mt-lg">
<div class="col q-mb-md">
<q-input
v-model="formData.email"
outlined
class="col"
label="Email"
ref="email"
stack-label
:rules="[ val => validateEmail(val) || 'Please enter a valid email address']"
lazy-rules />
</div>
<div class="col q-mb-md">
<q-input
v-model="formData.password"
type="password"
outlined
class="col"
label="Password"
ref="password"
stack-label
:rules="[ val => val.length >= 8 || 'Password must be at least 8 characters']"
lazy-rules />
</div>
<div class="row">
<q-btn
type="submit"
name="login"
class="login"
color="primary"
label="Login" />
</div>
</form>
</div>
</template>
Action method with api call:
submitForm () {
this.$refs.email.validate()
this.$refs.password.validate()
if (!this.$refs.email.hasError && !this.$refs.password.hasError) {
authService.login({ email: this.formData.email.toLowerCase(), password: this.formData.password })
.then((res) => {
this.$store.commit('SET_AUTH_USER')
localStorage.setItem('access_token', res.access_token)
localStorage.setItem('refresh_token', res.refresh_token)
this.$store.dispatch('GET_ME').then((me) => {
this.$router.push({ path: '/' })
})
}).catch((err) => {
if (err.status === 500) {
this.$swal({ icon: 'error', title: 'Something went wrong!' })
} else {
this.$swal({ icon: 'error', title: 'Wrong data!' })
}
})
}
}
My api call:
/**
* Send request for login user and set token in localstorage
*
* #param {String} email
* #param {String} password
* #returns {Object}
*/
async function login (data) {
const requestOptions = {
method: 'POST',
headers: {
'Content-Type': 'application/x-www-form-urlencoded',
Accept: 'application/json'
},
body: `email=${data.email.trim()}&password=${data.password.trim()}`
}
const res = await fetch('http://localhost/api/login', requestOptions)
if ((await res.status) !== 200) {
// eslint-disable-next-line no-throw-literal
throw { status: res.status, message: res.statusText }
} else {
return await res.json()
}
}
I read that I have to mock the action from vuex store and to trigger the action. So my test looks like this:
import Vuex from 'vuex'
import { mount, createLocalVue } from '#vue/test-utils'
import LoginComponent from '../components/Auth/Login'
const localVue = createLocalVue()
localVue.use(Vuex)
describe('Login form', () => {
it('calls the login action correctly', () => {
const loginMock = jest.fn(() => Promise.resolve())
const store = new Vuex.Store({
actions: {
// mock function
submitForm: loginMock
}
})
const wrapper = mount(LoginComponent, { localVue, store })
wrapper.find('form').trigger('submit.prevent')
expect(loginMock).toHaveBeenCalled()
})
})
The test is failed:
Login form
✕ calls the login action correctly (50 ms)
● Login form › calls the login action correctly
expect(jest.fn()).toHaveBeenCalled()
Expected number of calls: >= 1
Received number of calls: 0
18 | const wrapper = mount(LoginComponent, { localVue, store })
19 | wrapper.find('form').trigger('submit.prevent')
> 20 | expect(loginMock).toHaveBeenCalled()
| ^
21 | })
22 | })
23 |
at Object.<anonymous> (src/specs/login.spec.js:20:23)
Can you give me a suggestions what are the tests (not only the for api call) I need to write to make sure my form works correctly? Thank you!
You have to await the trigger since it is making an asyn function call
await wrapper.find('form').trigger('submit.prevent')
then
wrapper.$nextTick(() => {
expect(loginMock).toHaveBeenCalled()
})
amend the last bit. You omitted vm.
wrapper.vm.$nextTick(() => { expect(loginMock).toHaveBeenCalled(); });

REACTJS AND API pass the value of Api to another page

I really need help cause I'm totally new to reactjs. How can I maintain the logged-in user throughout the page? like a session. the code shows the data called when I logged in. I'm really lost here in react.
When the credentials are true, here's the result
{userId: 1, firstname: "Jeff", middlename: null, lastname: "Geli", positionId: 1, …}
userId: 1
firstname: "Jeff"
middlename: null
lastname: "Geli"
positionId: 1
token: "eyJhbGciOiJodHRwOi8vd3d3LnczLm9yZy8yMDAxLzA0L3htbGRzaWctbW9yZSNobWFjLXNoYTI1NiIsInR5cCI6IkpXVCJ9.eyJMb2dnZWRVc2VyIjoie1wiVXNlcklkXCI6MSxcIkZpcnN0bmFtZVwiOlwiSmVmZlwiLFwiTWlkZGxlbmFtZVwiOm51bGwsXCJMYXN0bmFtZVwiOlwiR2VsaVwiLFwiUG9zaXRpb25JZFwiOjEsXCJUb2tlblwiOm51bGx9IiwiZXhwIjoxNTc5NzU5MzI5LCJpc3MiOiJzbWVzay5pbiIsImF1ZCI6InJlYWRlcnMifQ.xXPW0ijBdULuMBfhFGyL1qF1bA--FzG64jEJVMQZWY8"
__proto__: Object
import React from 'react';
import { Link, withRouter } from 'react-router-dom';
import { PageSettings } from './../../config/page-settings.js';
import bg from '../../assets/login-bg-17.jpg';
import axios from "axios";
class LoginV2 extends React.Component {
static contextType = PageSettings;
constructor(props) {
super(props);
//credentials for login
this.state = {
username: '',
password: '',
};
this.handleSuccess = this.handleSuccess.bind(this);
this.handleChange = this.handleChange.bind(this);
this.handleSubmit = this.handleSubmit.bind(this);
}
componentDidMount() {
this.context.handleSetPageSidebar(false);
this.context.handleSetPageHeader(false);
}
componentWillUnmount() {
this.context.handleSetPageSidebar(true);
this.context.handleSetPageHeader(true);
}
handleChange(event) {
this.setState({
[event.target.name]: event.target.value
});
};
handleSuccess(data) {
alert("Logged IN");
this.props.history.push('dashboard/v2');
}
//When submit button is clicked, fetch API
async handleSubmit(event) {
event.preventDefault();
//fetch API, method POST
const getCred = await fetch('/api/login', {
headers: {
'Accept': 'application/json',
'Content-Type': 'application/json',
'ApiKey': "Secret"
},
method: "POST",
body: JSON.stringify({
username: this.state.username,
password: this.state.password
}),
});
const data = await getCred.json();
if (getCred.status == 400) {
alert(data);
} else {
this.handleSuccess(getCred);
}
console.log(data);
}
render() {
return (
<React.Fragment>
<div className="login-cover">
<div className="login-cover-image" style={{backgroundImage:'url('+ bg +')'}} >
</div>
<div className="login-cover-bg"></div>
</div>
<div className="login login-v2">
<div className="login-header">
<div className="brand">
<span className="logo"></span> <b>Tek</b> Teach
<small>Leraning Management System</small>
</div>
<div className="icon">
<i className="fa fa-lock"></i>
</div>
</div>
<div className="login-content">
<form className="margin-bottom-0" onSubmit={this.handleSubmit}>
<div className="form-group m-b-20">
<input type="text" className="form-control form-control-lg" placeholder="Username" name="username" value={this.state.username} onChange={this.handleChange} required />
</div>
<div className="form-group m-b-20">
<input type="password" className="form-control form-control-lg" placeholder="Password" name="password" value={this.state.password} onChange={this.handleChange} required />
</div>
<div className="login-buttons">
<button type="submit" className="btn btn-success btn-block btn-lg" onClick={this.login}>Sign me in</button>
</div>
</form>
</div>
</div>
</React.Fragment>
)
}
}
export default withRouter(LoginV2);
You could use sessionStorage or localStorage to store the token and then check for it, if it is set then keep user logged in otherwise logout user.
set the session once user logged in
if (token) {
localStorage.setItem('session', JSON.stringify(token));
}
To check if the user is logged in
let user = localStorage.getItem('session');
if (user) {
console.log('Valid session');
} else {
console.log('Not valid session');
}
On logut clear the value
let user = localStorage.getItem('session');
if (user) {
localStorage.removeItem();
}
Adding the logic in the provided code
async handleSubmit(event) {
// .... Other code
const data = await getCred.json();
if (data.status == 400) {
alert(data);
} else {
this.handleSuccess(data);
}
console.log(data);
}
//Set your token in handleSuccess method
handleSuccess(data) {
alert("Logged IN");
if (data.token) {
localStorage.setItem('session', JSON.stringify(data.token));
}
this.props.history.push('dashboard/v2');
}

"user.profile" undefined despite its declaration in Accounts.createUser()

I am working on a "settings" page where a logged in user can change their profile picture. However it seems that Meteor is having trouble finding the profile attribute for a user.
signup.js (here is where I create the user on signup and create the profile attribute)
import React, { Component } from 'react';
import { browserHistory } from 'react-router';
export default class Signup extends Component {
handleSubmit(event) {
event.preventDefault();
var signupEmail = event.target.signupEmail.value;
var signupPassword = event.target.signupPassword.value;
if (signupPassword !== '') {
Accounts.createUser({
email: signupEmail,
password: signupPassword,
profile: {
avatar: "/user-default.svg"
}
}, (err) => {
err ? (console.log(err.reason)) : browserHistory.push("/app/profile");
});
}
}
render() {
return (
<div className="login-form">
<form onSubmit={this.handleSubmit}>
<div className="input-options">
<input type="text" placeholder="Email" name="signupEmail" />
</div>
<div className="input-options">
<input type="password" placeholder="Password" name="signupPassword" />
</div>
<button className="login-submit bold">Sign me up!</button>
</form>
</div>
);
}
}
profile_settings.js
import React, { Component } from 'react';
import { Link } from 'react-router';
import reactMixin from 'react-mixin';
import ReactMeteorData from 'meteor/react-meteor-data';
export default class ProfileSettings extends Component {
constructor(props) {
super(props);
this.state = {
avatar: this.props.user.profile.avatar
}
}
getMeteorData(){
return{
user: Meteor.user()
}
}
componentWillMount(){
// we create this rule both on client and server
Slingshot.fileRestrictions("avatar", {
allowedFileTypes: ["image/png", "image/jpeg", "image/gif"],
maxSize: 2 * 500 * 500
});
}
upload(){
var userId = Meteor.user()._id;
var metaContext = {avatarId: userId};
var uploader = new Slingshot.Upload("UsersAvatar", metaContext);
uploader.send(document.getElementById('input').files[0], function (error, downloadUrl) { // you can use refs if you like
if (error) {
// Log service detailed response
console.error('Error uploading', uploader.xhr.response);
alert (error); // you may want to fancy this up when you're ready instead of a popup.
}
else {
// we use $set because the user can change their avatar so it overwrites the url :)
Meteor.users.update(Meteor.userId(), {$set: {"profile.avatar": downloadUrl}});
}
// you will need this in the event the user hit the update button because it will remove the avatar url
this.setState({avatar: downloadUrl});
}.bind(this));
}
formSubmit(){
let avatarUrl = this.state.avatar;
Meteor.users.update( {_id: Meteor.userId() }, {
$set: {profile: avatarUrl}
});
}
render() {
return (
<div>
<div className="sticky-header">
<h3>Settings</h3>
</div>
<form>
<div className="row well">
<div className="col-md-6">
<div className="form-group">
<label htmlFor="exampleInputFile">File input</label>
<input type="file" id="input" onChange={this.upload.bind(this)} />
<p className="help-block">Image max restriction: 2MB, 500x500. Cropped: 200x200</p>
</div>
</div>
<div className="col-md-6 utar-r">
<img src={this.state.avatar} height="200" width="200" alt="..." className="img-rounded" />
</div>
<div className="form-group">
<button className="btn btn-lg btn-primary btn-block" type="submit" onClick={this.formSubmit.bind(this)}>Update Profile</button>
</div>
</div>
</form>
<footer className="sticky-footer">
<Link to="/app/profile">
<button className="profile-edit bg-black">
<h3>Cancel</h3>
</button>
</Link>
<Link to="">
<button className="profile-edit">
<h3>Save Changes</h3>
</button>
</Link>
</footer>
</div>
);
}
}
reactMixin(ProfileSettings.prototype, ReactMeteorData);
Here is the error I am getting: TypeError: Cannot read property 'profile' of undefined
The error is not failing to find an profile attribute, but says that there's no user (or that user is undefined) This is exactly what TypeError: Cannot read property 'profile' of undefined means.
There are a few errors in your code:
the return of getMeteorData is available under this.data and not this.props
getMeteorData will run after constructor so there's no way to get Meteor's data in the constructor
getMeteorData returns data reactively, and is likely not to have the data you want when you instantiate the class anyway
So I'd recommend using the container/component approach that is like:
export default class ProfileSettingsContainer extends Component {
getMeteorData(){
return{
user: Meteor.user()
}
}
render() {
const user = this.data.user;
if (user) {
return <ProfileSettings user={user} />
} else {
return null; // or what ever placeholder you want while the data is being loaded
}
}
}
class ProfileSettings extends Component {
constructor(props) {
super(props);
this.state = {
avatar: props.user.profile.avatar
}
}
}
with this structure, the ProfileSettings will instantiate with something under props.user
Finnaly,
Meteor.users.update( {_id: Meteor.userId() }, {
$set: {profile: avatarUrl}
});
should be
Meteor.users.update( {_id: Meteor.userId() }, {
$set: {'profile.avatar': avatarUrl}
});
but that's unrelated

Categories