GOAL:
I am making a login by Google functionality in my website using Firebase Auth. I want When the user clicks the Signin link in the Navbar, he is redirected to the login page, in the login page, there is a dummy email/password input form and a Login with Google Button. When the user clicks on the Login with Google button he should be redirected to all the email list, so that he can choose from which he wants to login.
ERROR:
When the user clicks on the Signin Link in the Navbar the Login Route opens up and the function for the firebase auth is called by itself, without even clicking the Google Signin Button and the user is redirected to the emails list page.
Login.jsx:
import React from 'react'
import {Link} from "react-router-dom"
import './components/css/login.css'
import googleLogo from "./components/svg/google.svg"
import brandLogo from "./components/img/logo1.png"
//The JS for Login is in another file
import { googleSignin } from './firebase/googleLogin'
function login() {
return (
<div className="background-div" >
<nav className="login-nav" >
<img src={brandLogo} alt="logo"/>
<h2>the<strong>Dukaandar</strong></h2>
</nav>
<form action="" className="login-form">
<h3><strong>Login into your account</strong></h3>
<h5 className="login-email" >Email</h5>
<input type="text" className="login-email-input" placeholder="Enter your email" />
<h5 className="login-password">Password</h5>
<input type="password" className="login-password-input" placeholder="Enter your password" />
<br />
<button className="login-button">Login</button>
<Link className="login-forgot-password">forgot password?</Link>
<hr />
// The onClick attribute in React, I expect anything to happen only after clicking this button
<button className="google-login" onClick={googleSignin()} > <span className="google-image"><img src={googleLogo} alt=""/></span>Login with Google</button>
<Link to={"/"}>Back to Home</Link>
</form>
</div>
)
}
export default login
JS File:
import firebase from 'firebase'
const firebaseConfig = {
// Key value pairs of my config
};
// Initialize Firebase
firebase.initializeApp(firebaseConfig);
//This is the Function which has to be called on button click
function googleSignin() {
var provider = new firebase.auth.GoogleAuthProvider();
firebase
.auth()
.signInWithRedirect(provider)
.then(function(result) {
// This gives you a Google Access Token. You can use it to access the Google API.
var token = result.credential.accessToken;
// The signed-in user info.
var user = result.user;
console.log(user);
console.log(result);
})
.catch(function(error) {
console.log(error);
});
}
export { googleSignin }
While searching for it I came to know about lifecycle methods which occurs when the component is rendered, if that is the case here, how to stop them to call itself?
As told in answer below and from my finding onClick{ () => googleSignin } also does not work, and also when I call the function with parenthesis googleSignin(), the function is atleast called but withot it nothing hapens.
I suspect there can be a React Router problem also, but I don't know.
Thank you in advance
Full Source Code of the Website on Github,
Live Preview on Netlify
By adding parenthesis on the onClick handler, you are invoking the function as soon as it is loaded. Remove the parenthesis and it will work.
<button className="google-login" onClick={googleSignin}>
<span className="google-image">
<img src={googleLogo} alt="" />
</span>
Login with Google
</button>
When the Browser sees the function is being called and not referenced on the OnClick method, it takes the responsibility and calls the function by itself. So, we have to free the Browser from its responsibility, and let the Function to be called only when the User clicks on the button.
Make a Handler function to free the Browser from its responsibility:
function handleClick(e) {
e.preventDefault();
googleSignin();
console.log('The link was clicked.');
}
Reference handleClick in your onClick method:
<button className="google-login"
//Reference handleClick here.
onClick={handleClick}>
<span className="google-image">
<img src={googleLogo} alt=""/>
</span>
Login with Google
</button>
This will solve the problem.
Related
I am working on a login form, and I am getting a strange behavior whereby whenever I click on the 'Login' button, the page simply reloads, without logging in my email and password through the 'submitHandler' function.
Below is a code of the form (I removed a lot of extra CSS formatting and div's).
Here is a screenshot of the form:
loginForm
import React from 'react'
import { useState, useEffect } from "react";
import { useDispatch, useSelector } from "react-redux";
import { login } from "../../../actions/userActions";
import { Form, Button, Row, Col } from "react-bootstrap";
function LoginForm ({history}) {
const [email, setEmail] = useState("");
const [password, setPassword] = useState("");
const submitHandler = (e) => {
e.preventDefault();
console.log(email, password)
// dispatch(login(email, password));
};
return (
<form>
<button onSubmit={submitHandler} type="submit">
Login
</button>
</form>
)
}
export default LoginForm
Does anyone have idea why the page reloads after clicking on the login button?
Issue
The button is of type="submit" but the form has no onSubmit handler and is thus taking the default form action, i.e. submitting the form and reloading the page.
Solution
Move the onSubmit to the form element so the callback can prevent the default form action from occurring.
<form onSubmit={submitHandler}>
<button type="submit">
Login
</button>
</form>
You can also convert button type="" method provider submit to button, in some cases you don't really want to submit internal form so just keep in mind.
Here is the example,
<form>
<button onSubmit={submitHandler} type="button">
</form>
Other answer is also OK, but I would like to approach from a different angle.
Try calling the submitHandler with onSubmit on the form instead of on the button.
I have a react component
const Header = () => {
return(
<div role="button" className="user-logout" onClick={logoutUser}>
<i className="fas fa-sign-out-alt user--nav--icon"></i>
Logout
</div>
)}
In the above code onClick logout the user gets logged out
const logoutUser = () => {
dispatch(logout());
history.push('/login');
};
but I want the user to get a message popup onClcik in a div with conforming logout or cancel
and then on confirming logout it should logout the user
You can pass a GET Parameter to the login page like:
history.push('/login?logout=1');
Then if the login page has this parameter, render your message.
If you don't want to use a parameter, you will have to look for another solution either with react context or react navigation
For example, I created a Root Component named Index.vue, and Registred these 3 Login, Agree and Validation. What I'm picturing out is, after click submit button inside Login, the Agree.vue is showed and successively is happen when I click submit button inside Agree.
I think that I should use prop data to passing among components a state about each components, that way trigged a command to show the component that I want. But how I should "hide" the other components. I don't know if there a way to register the component at the moment submit form inside each Login, Agree, ...
<template>
<v-app>
<Login />
<Agree />
<Validation />
</v-app>
</template>
<script>
export default {
components:{
Login: () => import('./components/Login'),
Agree: () => import('./components/Agree-Term')
Validation: () => import('./components/Validation')
}
}
</script>
I am using Nuxt and Vue and I am trying to submit a form, redirect the user to a new route including the submitted params, send an API request to get some data and then render that data.
I achieved this by simply setting the form action to the new path and manually adding all the URL parameters to the API request.
First I create a simple form with the route /search.
<form action="/search">
<input type="text" name="foobar">
<button type="submit">Submit</button>
</form>
When submitting the form the user leaves the current page and gets redirected to the new page. The URL would now look like this: http://www.example.com/search?foobar=test. Now I fetch the foobar parameter by using this.$route.query.foobar and send it to my API.
However the problem in my approach is when submitting the form the user leaves the current page and a new page load will occur. This is not what we want when building progressive web apps.
So my question is how can I submit a form in Nuxt/Vue and redirect to a new route including the submitted parameters?
The default behavior of <form> is to reload the page onsubmit. When implementing SPA's it would be better to avoid invoking default behavior of <form>.
Making use of router module which is available out-of-box in nuxtjs will enable all the redirection controls to flow within the application. if we try to trigger events available via <form> then browser reload will occur. This has to be avoided.
So my question is how can I submit a form in Nuxt/Vue and redirect to
a new route including the submitted parameters?
You can try below approach
First
Use .stop.prevent modifiers to prevent the submit button from invoking default <form> behavior. This is similar to using event.stopPropagation(); and event.preventDefault(); in jQuery
<form>
<input type="text" name="foobar" v-model="foobar">
<button type="submit" #click.stop.prevent="submit()">Submit</button>
</form>
Then
Create
vue model object foobar
vue method submit
Use this.$router.push to redirect to next page. This will enable the control flow to stay inside the SPA. if you want to send any data into server then you can do it before invoking this.$router.push else you can redirect and continue your logic.
export default {
data(){
return {
foobar : null
}
},
methods: {
submit(){
//if you want to send any data into server before redirection then you can do it here
this.$router.push("/search?"+this.foobar);
}
}
}
submitClick(){
this.$router.push({path: '/search', query:{key: value}})
}
<form #submit.stop.prevent="submitClick">
<input v-model="keyword">
<button type="submit">Search</button>
</form>
This is the right way to achieve a SPA with form submit. it supports enter key and in submitClick, there can be any logic before submitting
just add this:
#submit.prevent="false"
<form #submit.prevent="false">
<div class="form-group">
</div>
</form>
i hope this be useful for u :)
I've been trying to add simple email / password signup/login for Firebase to the Polymer Starter Kit app. It comes stock with a Google auth sign in via a single button but there doesn't seem to be any instructions on how to set-up email/password register/login instead.
Here is the specific part of the code from the project's todo-auth.html file I've been struggling with:
<firebase-auth id="authenticate"
user="{{user}}"
location="{{location}}"
ref="{{refauth}}"
provider="">
</firebase-auth>
<paper-dialog modal
opened="[[!user]]"
entry-animation="scale-up-animation"
exit-animation="fade-out-animation">
<h2>Please sign in</h2>
<div>
<!-- Inputs I added to accept user credentials -->
<paper-input id="loginEmailInput"
no-label-float
label="Email"
on-keydown="">
</paper-input>
<paper-input id="loginPasswordInput"
no-label-float
label="Password"
on-keydown="">
</paper-input>
<paper-button on-tap="logIn">Login</paper-button>
<!-- Original Google sign-in code -->
<!-- <div class="google-sign-in"
tabindex="0"
on-tap="signIn">
<span class="google-sign-in-icon"></span>
<span class="google-sign-in-label">Google</span>
</div> -->
</div>
</paper-dialog>
I removed google from the provider property of the <firebase-auth> element and added a couple of input fields but don't really know where to go from there.
Here is the Polymer script part of todo-auth.html
<script>
Polymer({
is: 'todo-auth',
properties: {
user: {
notify: true
}
},
logIn: function() {
this.$.authenticate.login();
},
signOut: function() {
this.$.authenticate.logout();
this.user = null;
}
});
</script>
I've tried to find examples or guide tutorials on how to implement this but everything I've found has used the google based auth as login. Likewise, all other questions I've found here on SO have focused on google login.
I'd be grateful for any directions or pointers or tutorials on how to set it up. Thanks all in advance!
UPDATE
I managed to implement a new page with a form using the demo from the Google Web Components github repo.
I have a my-firebase.html file that imports everything I can think of to make it work. Imports look like this:
<link rel="import" href="../../bower_components/polymer/polymer.html">
<link rel="import" href="../../bower_components/polymerfire/firebase-auth.html">
<link rel="import" href="../../bower_components/polymerfire/firebase-app.html">
<link rel="import" href="../../bower_components/polymerfire/polymerfire.html">
I have also added the following for firebase-app and firebase-auth:
<firebase-app auth-domain="my-polymer-app.firebaseapp.com"
database-url="https://my-polymer-app.firebaseio.com/"
api-key="xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx">
</firebase-app>
<firebase-auth id="firebaseLogin" user="{{user}}" status-known="{{statusKnown}}" location="my-polymer-app.firebaseapp.com" provider="{{provider}}" on-error="errorHandler" on-user-created="userSuccessHandler" on-password-changed="us erSuccessHandler" on-password-reset="userSuccessHandler" on-user-removed="userSuccessHandler"></firebase-auth>
I am now getting the following error when I try to login(I have already set up a user in my Firebase App to test):
my-firebase.html:122 Uncaught TypeError: this.$.firebaseLogin.login is not a function
Which refers to this part of the code take from the Google Web Components repo.
login: function() {
var params;
try {
params = JSON.parse(this.params);
} catch (e) {
params = null;
}
if (this.provider == 'password') {
params = params || {};
params.email = this.email;
params.password = this.password;
}
this.$.firebaseLogin.login(params);
}
There are also red boxes around every instance of firebaseLogin on the page. No other errors are showing up so not sure what this means exactly. Again, I'd be grateful if anyone could point out what I'm missing here.
Use signInWithEmailAndPassword function instead of login function,
this.$.firebaseLogin.signInWithEmailAndPassword(username, password);