Firebase phone number authentication with Vue.js does not work - javascript

I am building a new Vue.js app based on the Webpack template. I have a /sign-in route that loads a component called SignIn. I am trying to use Firebase Phone Number authentication using the Firebase SDK to authenticate my users.
I've installed Firebase with npm install firebase and initialized it in my main.js file like this:
/src/main.js
import firebase from 'firebase';
import Vue from 'vue';
import App from './App';
import router from './router';
Vue.config.productionTip = false;
// Initialize Firebase
const config = {
apiKey: 'MY_API_KEY',
authDomain: 'MY_PROJECT.firebaseapp.com',
databaseURL: 'https://MY_PROJECT.firebaseio.com',
projectId: 'MY_PROJECT_ID',
storageBucket: 'MY_PROJECT.appspot.com',
messagingSenderId: 'MY_SENDER_ID',
};
firebase.initializeApp(config);
/* eslint-disable no-new */
new Vue({
el: '#app',
router,
template: '<App/>',
components: { App },
});
My credentials are redacted for security in the above example.
When the user is on /sign-in, this is the component that they see:
/src/components/pages/SignIn.vue
<template>
<div>
<!-- Number Input Form -->
<div v-if="showNumberInput">
<form v-on:submit.prevent>
<div class="form-group">
<input type="text" class="form-control form-control-lg" v-model="numberInputForm.number" placeholder="Phone number" required>
</div>
<div class="form-group">
<button type="submit" id="get-sign-in-code" class="btn btn-block btn-lg success theme-accent">{{ getSignInCodeButton.text }}</button>
</div>
</form>
</div>
<!-- SMS Verification Form -->
<div v-if="showCodeInput">
<form>
<div class="form-group">
<input type="text" class="form-control form-control-lg" value="9944" placeholder="Verification Code" required>
</div>
<div class="form-group">
{{ signInButton.text }}
</div>
</form>
</div>
</div>
</template>
<script>
import firebase from 'firebase';
export default {
name: 'SignIn',
data() {
return {
// UI States
showNumberInput: true,
showCodeInput: false,
// Forms
numberInputForm: {
number: '',
},
// Buttons
getSignInCodeButton: {
text: 'Get sign in code',
},
signInButton: {
text: 'Sign in',
},
};
},
mounted() {
const self = this;
// Start Firebase invisible reCAPTCHA verifier
window.recaptchaVerifier = new firebase.auth.RecaptchaVerifier('get-sign-in-code', {
'size': 'invisible',
'callback': (response) => {
// reCAPTCHA solved, allow signInWithPhoneNumber.
self.sendSMS();
}
});
},
methods: {
/**
* Sends the user an SMS-verification code using Firebase auth
*
* #see https://firebase.google.com/docs/auth/web/phone-auth
*/
sendSMS() {
const self = this;
self.getSignInCodeButton = {
showSpinner: true,
text: 'Sending SMS..',
disabled: true,
};
},
/**
* Authenticates the user with Firebase auth
*/
signIn() {
// Redirect the user to the authenticated page
},
},
};
</script>
As you can see, I have two forms in the template - one to capture the phone number and another to allow the user to enter the verification code. I am toggling the visibility of these forms programmatically.
When the component mounts, I am calling the Firebase reCAPTCHA verifier and passing the ID of the submit button ("get-sign-in-code" in this case). However, when I click the button, nothing happens. I don't see the reCAPTCHA XHR in my dev tools network tab.
Could this be because the button is being inserted into the DOM dynamically and firebase.auth.RecaptchaVerifier() cannot detect it when I pass the ID when the component mounts? How do I resolve this? Could I use $el or some other Vue.js method to get the reCAPTCHA verifier to work? Thanks.
UPDATE
I was able to get this script to work by adding the following lines to the mounted() event:
window.recaptchaVerifier.render().then((widgetId) => {
window.recaptchaWidgetId = widgetId;
});
This is how my mounted() method looks like now:
mounted() {
const self = this;
// Start Firebase invisible reCAPTCHA verifier
window.recaptchaVerifier = new firebase.auth.RecaptchaVerifier('get-sign-in-code', {
size: 'invisible',
callback: () => {
// reCAPTCHA solved, allow signInWithPhoneNumber.
self.sendSMS();
},
});
window.recaptchaVerifier.render().then((widgetId) => {
window.recaptchaWidgetId = widgetId;
});
},
This however cause a new issue - the script now adds a randomly positioned "Protected by reCAPTCHA" badge that I'd like to get rid off. Is there any way to get this script to work without showing the badge?

I guess it is late to answer. But I see in your code when mounted() hook appeared you call sendSMS() function in recaptchaVerifier after callback. But when on subbitting first button which is:
<button type="submit" id="get-sign-in-code" class="btn btn-block btn-lg success theme-accent">{{ getSignInCodeButton.text }}</button>
no function showed to call on submit or on click. I guess you would update your button to react clicking on it like below: change is in form tag that showing which function to call on submit form.
<div v-if="showNumberInput">
<form v-on:submit.prevent="sendSMS">
<div class="form-group">
<input type="text" class="form-control form-control-lg" v-model="numberInputForm.number" placeholder="Phone number" required>
</div>
<div class="form-group">
<button type="submit" id="get-sign-in-code" class="btn btn-block btn-lg success theme-accent">test</button>
</div>
</form>
</div>

If anyone using nuxt.js (vuejs framework) then follow these steps
Inside your nuxt.config.js add the follwoing lines
import 'firebase/compat/auth'; //import this on the top and
modules: [
...// other code
[
'#nuxtjs/firebase',
{
config: {
apiKey: '<apiKey>',
authDomain: '<authDomain>',
projectId: '<projectId>',
storageBucket: '<storageBucket>',
messagingSenderId: '<messagingSenderId>',
appId: '<appId>',
measurementId: '<measurementId>'
},
services: {
auth: true // Just as example. Can be any other service.
}
}
]
],
then inside your file wherever you want to use phone authentication first import firebase like this
<template>
///
</template>
<script>
import firebase from 'firebase/compat/app';
methods : {
// configure recaptcha
configureRecaptcha() {
window.recaptchaVerifier = new firebase.auth.RecaptchaVerifier(
"otp-verfiy-button",
{
size: "invisible",
callback: (response) => {
sendOtpForVerification();
},
}
);
},
// handle otpsend
sendOtpForVerification() {
this.configureRecaptcha();
const phoneNumber = "+91" + this.userMobile; //user phone number
const appVerifier = window.recaptchaVerifier;
firebase.auth().languageCode = "en";
firebase.auth()
.signInWithPhoneNumber(phoneNumber, appVerifier)
.then((confirmationResult) => {
// SMS sent. Prompt user to type the code from the message, then sign the
// user in with confirmationResult.confirm(code).
window.confirmationResult = confirmationResult;
this.$toast.success("Otp sent successfully");
})
.catch((error) => {
// Error; SMS not sent
console.log("Error", error);
});
},
}
</script>
please make sure you have installed firebase and #nuxtjs/firebase
hope this will help somebody :)

Use sign-in-button do "Protected by reCAPTCHA"

Related

How to I fix an http error code 400? (firebase auth related)

I have a static website where I am trying to configure it to communicate with firebase particularly the authentication bit, but I have 2 errors displaying in the console Console network tab view console: network tab waterfall view
now what is happening exactly is that I made a single html page to handle authentication
this page is called (auth.html)
// Import the functions you need from the SDKs you need
import { initializeApp } from 'https://www.gstatic.com/firebasejs/9.8.4/firebase-app.js';
import { getAuth, onAuthStateChanged, signInWithEmailAndPassword, createUserWithEmailAndPassword, signInWithCustomToken, signOut } from "https://www.gstatic.com/firebasejs/9.8.4/firebase-auth.js";
// Your web app's Firebase configuration
// Initialize Firebase
const app = initializeApp({
apiKey: "API key",
authDomain: "firebaseapp.com",
databaseURL: "https://firebaseio.com",
projectId: "fireauth",
storageBucket: "appspot.com",
messagingSenderId: "162620739",
appId: "1:16262739:web:634d6f3357004eced9e"
});
// Above initialization details are incorrect deliberately (they aren't the issue/ focus now)
const auth = getAuth(app);
createUserWithEmailAndPassword(auth, email, password)
.then((userCredential) => {
// Signed in
const user = userCredential.user;
// ...
})
.catch((error) => {
const errorCode = error.code;
const errorMessage = error.message;
// ..
});
signInWithEmailAndPassword(auth, email, password)
.then((userCredential) => {
// Signed in
const user = userCredential.user;
// ...
})
.catch((error) => {
const errorCode = error.code;
const errorMessage = error.message;
});
signInWithCustomToken()
.then((userCredential) => {
// Signed in
var user = userCredential.user;
// ...
})
.catch((error) => {
var errorCode = error.code;
var errorMessage = error.message;
// ...
});
// Detect auth state
onAuthStateChanged(auth, (user) => {
if (user) {
// User is signed in, see docs for a list of available properties
// https://firebase.google.com/docs/reference/js/firebase.User
const uid = user.uid;
// ...
console.log("Logged in!");
alert("You are logged in!");
} else {
// User is signed out
// ...
console.log("Anonymous mode (signed out)");
}
});
signOut(auth).then(() => {
// Sign-out successful.
console.log("logged out")
}).catch((error) => {
// An error happened.
alert("Network error");
});
<body>
<!--- Login section --->
<div id="login-div" class="container">
<div class="div1">
<form class="login-form"><h1>Login to continue</h1>
<p>Avatar ID</p>
<input type="text" id="email" placeholder="Email" required>
<p>Secret Key</p>
<input type="password" id="password" placeholder="Password" required>
<button type="signInWithEmailAndPassword" disabled>Login</button><br><a onclick="thenewcallout3()" href="#">Reset my secret key</a>
</form>
</div>
</div>
<!--- register section --->
<div id="user-div" class="div2">
<form class="login-form">
<h2>Register to continue</h2><br>
<p>Enter your email address</p>
<input type="email" placeholder="Avatar ID" id="avatarId" required>
<p>Password</p>
<input type="text" placeholder="Secret key"><br><br>
<input type="password" placeholder="Repeat your secret key" id="secretKey" required><br><br>
<p id="up">I accept that my privacy & actions online are my responsibility not StarlinkBw</p><input type="checkbox" required>
<button type="createUserWithEmailAndPassword" disabled>Register</button>
</form></div>
<!---Account reset--->
<div class="fixAcc"><h1>Password reset</h1><input type="email" placeholder="Enter your Avatar ID"><br><br><button disabled>Request new key</button></div>
<!--- Portal --->
<nav class="menu">
<header>Starlink <span>[X]</span></header>
<ol>
<li class="menu-item">
Go back</li>
<!--- views registration form & hides login --->
<li class="menu-item"><a onclick="thenewcallout()" href="#" >Login</a></li>
<li class="menu-item"><a onclick="thenewcallout2()" href="#" >Register</a></li>
<ol class="sub-menu">
<li class="menu-item">
Social networking
</li>
<li class="menu-item">
Self care
</li>
<li class="menu-item">
Entertainment
</li>
<li class="menu-item">
Productivity
</ol>
<li class="menu-item">
Terms & Conditions
</li>
</ol>
</li>
<footer><button aria-label="Toggle Menu">Toggle</button></footer>
</nav>
<script src="../scripts/sl.js"></script>
<script src="../scripts/jl.js"></script>
<script type = 'text/javascript' src="../scripts/status-check.js"></script>
<!--- Firebase --->
<script src="../scripts/sync.js" type="module"></script>
</body>
which is linked to a JavaScript file called ./sync.js.
I managed to initialize firebase successfully (I think) and reports the current user (me in dev mode) is logged out in the console <Console user view> (which is great news) but I am having trouble sending the user data from the static auth.html page to firebase. what is the issue with my sync.js file?
to see the current perfomance of the website in real life, you can visit My website please note all auth triggering buttons are disabled in the actual website so that I can fix this error.
I managed to fix to the problem
thanks to the advice Bravo gave me
I removed a few declaration like signingInWithCustomToken & signout (I am going need signout later though)
signing in using custom token is a little more complicated since it uses the Admin SDK which I failed several times trying to implement it.
I added event listeners to import data from specific input elements fields (most likely which caused the 400 error due to value assignment mismatch)
which turned my auth.html & sync.js to look like the code snippets attached
although Auth works, the system faces issues like (network errors) when ad-blockers are running/ enabled
as for the console there is nothing to report there, it doesnt show any errors anymore
This is the end result after authenticating Auth result within client & firebase updated
// Import the functions you need from the SDKs you need
import { initializeApp } from 'https://www.gstatic.com/firebasejs/9.8.4/firebase-app.js';
import { getAuth, signInWithEmailAndPassword, createUserWithEmailAndPassword, signOut } from "https://www.gstatic.com/firebasejs/9.8.4/firebase-auth.js";
// Your web app's Firebase configuration
// Initialize Firebase
const firebaseConfig = {
apiKey: "Your API key,
authDomain: "firebaseapp.com",
databaseURL: "firebaseio.com",
projectId: "your project",
storageBucket: "appspot.com",
messagingSenderId: "11739",
appId: "1:162621739:web:634d6f04eced9e"
};
// Again the above configurations are incorrect delibaratetly (but not the main focus)
// Initialize Firebase
const app = initializeApp(firebaseConfig);
const auth = getAuth(app);
submitData.addEventListener('click', (e) => {
var email = document.getElementById("email").value;
var password = document.getElementById("password").value;
createUserWithEmailAndPassword(auth, email, password)
.then((userCredential) => {
// Signed in
const user = userCredential.user;
// ...
alert("Account creation success! Welcome " + email);
window.location.replace("https://google.com");
})
.catch((error) => {
const errorMessage = error.message;
// ..
alert(errorMessage);
});
});
submitLogin.addEventListener('click', (f) => {
var avatar = document.getElementById("avatar").value;
var secretKey = document.getElementById("secretKey").value;
signInWithEmailAndPassword(auth, avatar, secretKey)
.then((userCredential) => {
// Signed in
const user = userCredential.user;
// ...
alert("You are logged in as: " + avatar);
window.location.replace("https://google.com");
})
.catch((error) => {
const errorCode = error.code;
alert(errorCode);
});
});
<!--- Login section --->
<div class="container">
<form class="login-form"><h1>Login to continue</h1>
<p>Avatar ID</p>
<!--- Avatar & secretKey fields here --->
<input type="text" id="avatar" placeholder="Email" autocomplete="email">
<p>Secret Key</p>
<input type="password" id="secretKey" placeholder="Password" autocomplete="current-password">
<button type="button" id="submitLogin" name="submitLogin">Login</button><br><a onclick="thenewcallout3()" href="#">Reset my secret key</a>
</div>
<!---Register section ---->
<div class="div2">
<div class="login-form">
<h2>Register to continue</h2><br>
<p>Enter your email address</p>
<!----Email & password registration fields here ---->
<input type="email" placeholder="Avatar ID" id="email" autocomplete="email">
<p>Password</p>
<input type="password" placeholder="Secret key"><br><br>
<input type="password" placeholder="Repeat your secret key" id="password" autocomplete="new-password"><br><br>
<p id="up">I accept that my privacy & actions online are my responsibility not StarlinkBw</p><input type="checkbox">
<button id="submitData" name="submitData">Register</button></div>
</div>
Account reset section
<section>
<div class="fixAcc">
<h1>Password reset</h1>
<input placeholder="Enter your Avatar ID" autocomplete="email" id="email-P-Reset"><br>
<br>
<button>Request new key</button>
</div>
</section></form>
I see..., I Had the same problem Today and I realized that the configurations in my code was okay, what I need to do is go to my firebase console on project shortcuts and click on authentication -> go to sign-in Method and on the provider, make sure the email/password provider is enabled, if it's not added click on add provider and select email/password and then enable it

how to link submit button to another page in html [duplicate]

For some reason my loginAccount() function will not work. When creating an account with my createAccount() function, the DOM elements seem correct as the entered email and password are stored and update my Auth database in Firebase.
However, when trying to use the same login (that I just created) to actually log the user in, apparently Firebase is getting both a null email and password from the DOM elements, though the ids are correct.
I'm sure it's something very trivial, yet I have been working to fix this issue for some days now. Any pointers will help!
index.html
<html>
<head>
<title>Login</title>
<!-- The core Firebase JS SDK is always required and must be listed first -->
<script src="https://www.gstatic.com/firebasejs/7.14.2/firebase-app.js"></script>
<script src="https://www.gstatic.com/firebasejs/7.14.2/firebase-auth.js"></script>
<!-- TODO: Add SDKs for Firebase products that you want to use
https://firebase.google.com/docs/web/setup#available-libraries -->
<script src="https://www.gstatic.com/firebasejs/7.14.2/firebase-analytics.js"></script>
<link rel="stylesheet" type="text/css" href="style.css" />
</head>
<body>
<div class="loginbox">
<img src="avatar.png" class="avatar" />
<h1>Login Here</h1>
<form>
<p>E-mail</p>
<input type="email" placeholder="Enter E-mail" id="email" />
<p>Password</p>
<input type="password" placeholder="Enter Password" id="password" />
<button id="signUp" onclick="createAccount()">Sign Up</button>
<button id="signIn" onclick="loginAccount()">Login</button>
<button id="signOut" onclick="logOut()">Sign Out</button>
</form>
</div>
<script src="app.js"></script>
</body>
</html>
app.js
// Your web app's Firebase configuration
var firebaseConfig = {
apiKey: "AIzaSyC9AEwx8_GrHRT8uvFoNiK1DOk6IXITnGQ",
authDomain: "database-993c9.firebaseapp.com",
databaseURL: "https://database-993c9.firebaseio.com",
projectId: "database-993c9",
storageBucket: "database-993c9.appspot.com",
messagingSenderId: "856956039875",
appId: "1:856956039875:web:27ccd6b0d0bc806135a876",
measurementId: "G-JJYN70EV99",
};
// Initialize Firebase
firebase.initializeApp(firebaseConfig);
firebase.analytics();
const auth = firebase.auth();
// Create an account
function createAccount() {
const email = document.getElementById("email").value;
const pass = document.getElementById("password").value;
auth.createUserWithEmailAndPassword(email, pass).catch(function (error) {
// Handle Errors here.
var errorCode = error.code;
var errorMessage = error.message;
// ...
});
}
// Login to an account
function loginAccount() {
const email = document.getElementById("email").value;
const pass = document.getElementById("password").value;
auth.signInWithEmailAndPassword(email, pass).catch(function (error) {
// Handle Errors here.
var errorCode = error.code;
var errorMessage = error.message;
// ...
});
}
// Logout of an account
function logOut() {
auth
.signOut()
.then(function () {
// Sign-out successful.
console.log("signed out.");
})
.catch(function (error) {
// An error happened.
});
}
auth.onAuthStateChanged(function (user) {
if (user) {
// User is signed in.
console.log("user is signed in!");
} else {
// No user is signed in.
console.log("no user logged in.");
}
});
Your problem comes from the fact that your form is submitted before the Firebase methods are triggered.
As a matter of fact, you declare your button as follows:
<button id="signUp" onclick="createAccount()">Sign Up</button>
i.e. without any type attribute.
As detailed in the W3 specification on button types, "the missing value default is the Submit Button state" and "if the type attribute is in the Submit Button state, the element is specifically a submit button".
So, if you add a button type to your button, as follows, it should solve your problem.
<button type="button" id="signUp" onclick="createAccount()">Sign Up</button>

how to integrate firebase in webapp using android firebase database?

android database is create and i want to authenticate it using html page.
it is not working code is given below.
here basically we have a html login page and script to authenticate it from fire-base database.provide with the solution code or what's wrong with my code or something missing in it.
<!DOCTYPE html>
<html>
<head>
<!-- /////////////////firebase method ///////////////////// -->
<title>
the login form
</title>
<script src="https://www.gstatic.com/firebasejs/4.9.1/firebase.js"></script>
<script src="https://www.gstatic.com/firebasejs/4.9.0/firebase-app.js"></script>
<script src="https://www.gstatic.com/firebasejs/4.9.0/firebase-auth.js"></script>
<script src="https://www.gstatic.com/firebasejs/4.9.0/firebase-database.js"></script>
<script src="https://www.gstatic.com/firebasejs/4.9.0/firebase-firestore.js"></script>
<script src="https://www.gstatic.com/firebasejs/4.9.0/firebase-messaging.js"></script>
<script>
// Initialize Firebase
var config = {
apiKey: "AIzaSyBgFUWzUrmLXVuKtGtChe2I2zvf5sYga54",
authDomain: "skool-1083c.firebaseapp.com",
databaseURL: "https://skool-1083c.firebaseio.com",
projectId: "skool-1083c",
storageBucket: "skool-1083c.appspot.com",
messagingSenderId: "911580445409"
};
firebase.initializeApp(config);
</script>
</head>
<body>
<h1>Admin Login</h1>
<form class="form" action="new_blank">
<input type="text" placeholder="username" id="email"autofocus><br>
<input type="password" placeholder="pasword" id="password" ><br></br>
<input type="submit" value="login" id="sign-in">
<br>
</form>
<!-- ///////////////stylesheet///////////// -->
<script>
document.querySelector('#sign-in').addEventListener('click', function(e) {
e.preventDefault();
e.stopPropagation();
var email = document.querySelector('#email').value;
var password = document.querySelector('#password').value
var credential = firebase.auth.EmailAuthProvider.credential(email, password);
window.alert(credential);
var auth = firebase.auth();
var currentUser = auth.currentUser;
// Step 2
// Get a credential with firebase.auth.emailAuthProvider.credential(emailInput.value, passwordInput.value)
// If there is no current user, log in with auth.signInWithCredential(credential)
// If there is a current user an it's anonymous, atttempt to link the new user with firebase.auth().currentUser.link(credential)
// The user link will fail if the user has already been created, so catch the error and sign in.
});
</script>
</body>
</html>
If you want to sign in user with email+password on Firebase Authentication, follow the documentation here. From there, the example to sign in is:
firebase.auth().signInWithEmailAndPassword(email, password).catch(function(error) {
// Handle Errors here.
var errorCode = error.code;
var errorMessage = error.message;
// ...
});
To detect when a user signs in, follow the documentation here. From there:
firebase.auth().onAuthStateChanged(function(user) {
if (user) {
// User is signed in.
} else {
// No user is signed in.
}
});
implement firebase auth in app/build.gradle
implementation 'com.google.firebase:firebase-auth:18.1.0'
implementation 'com.google.firebase:firebase-database:18.0.1'
use enterd user id and password with this function
private void login() {
FirebaseAuth firebaseAuth=FirebaseAuth.getInstance();
firebaseAuth.signInWithEmailAndPassword(usrId, usrPass).addOnCompleteListener(loginActivity.this, new OnCompleteListener() {
#Override
public void onComplete(#NonNull Task task) {
if (!task.isSuccessful()) {
Toast.makeText(loginActivity.this, "Not sucessfull", Toast.LENGTH_SHORT).show();
} else {
startActivity(new Intent(loginActivity.this, MainActivity.class));
}
}
});

Passing BraintreeJS paymentnonce payload to ASP.NET Web Form

I'm trying to integrate Chargebee with Braintree using ChargeBee's API+BraintreeJS (easiest to get PCI compliance). Here is the link of methods that could be used (https://www.chargebee.com/docs/braintree.html). Based on that document, I can conclude that these are the steps
1) Generate clientToken using Braintree SDK for .NET
2) Use BraintreeJS to tokenize all hosted fields and send to Braintree API to get payment nonce
3) Use ChargeBee SDK for .NET and send payment nonce to create subscription in ChargeBee
I've managed to do (1) and (2) but my issue is how could I read the payment nonce during postback? I've tried using controller but still getting null value
Here's my code
<script>
var form = document.querySelector('#cardForm');
var authorization = '<%=clientToken%>';
braintree.client.create({
authorization: authorization
}, function (err, clientInstance) {
if (err) {
console.error(err);
return;
}
createHostedFields(clientInstance);
});
function createHostedFields(clientInstance) {
braintree.hostedFields.create({
client: clientInstance,
styles: {
'input': {
'font-size': '16px',
'font-family': 'courier, monospace',
'font-weight': 'lighter',
'color': '#ccc'
},
':focus': {
'color': 'black'
},
'.valid': {
'color': '#8bdda8'
}
},
fields: {
number: {
selector: '#card-number',
placeholder: '4111 1111 1111 1111'
},
cvv: {
selector: '#cvv',
placeholder: '123'
},
expirationDate: {
selector: '#expiration-date',
placeholder: 'MM/YYYY'
},
postalCode: {
selector: '#postal-code',
placeholder: '11111'
}
}
}, function (hostedFieldsErr, hostedFieldsInstance) {
if (hostedFieldsErr) {
console.error(hostedFieldsErr);
return;
}
submit.removeAttribute('disabled');
form.addEventListener('submit', function (event) {
event.preventDefault();
hostedFieldsInstance.tokenize(function (tokenizeErr, payload) {
if (tokenizeErr) {
console.error(tokenizeErr);
return;
}
// If this was a real integration, this is where you would
// send the nonce to your server.
var noncestr = payload.nonce
alert(noncestr); // Confirm nonce is received.
console.log('Got a nonce: ' + payload.nonce);
$('#paymentmethodnonce').attr("value", noncestr); // Add nonce to form element.
form.submit();
});
}, false);
});
}
</script>
<body>
<div class="demo-frame">
<form action="/" method="post" id="cardForm">
<label class="hosted-fields--label" for="card-number">Card Number</label>
<div id="card-number" class="hosted-field"></div>
<label class="hosted-fields--label" for="expiration-date">Expiration Date</label>
<div id="expiration-date" class="hosted-field"></div>
<label class="hosted-fields--label" for="cvv">CVV</label>
<div id="cvv" class="hosted-field"></div>
<label class="hosted-fields--label" for="postal-code">Postal Code</label>
<div id="postal-code" class="hosted-field"></div>
<div class="button-container">
<input type="submit" class="button button--small button--green" value="Purchase" id="submit" />
</div>
<asp:Label runat="server" ID="lblResult"></asp:Label>
</form>
</div>
<script src="https://js.braintreegateway.com/web/3.8.0/js/client.js"></script>
<script src="https://js.braintreegateway.com/web/3.8.0/js/hosted-fields.js"></script>
</body>
</html>
public partial class Default : System.Web.UI.Page
{
protected string clientToken;
private BraintreeGateway gateway = new BraintreeGateway
{
Environment = Braintree.Environment.SANDBOX,
MerchantId = "xxx",
PublicKey = "xxx",
PrivateKey = "xxx"
};
protected void Page_Load(object sender, EventArgs e)
{
if (!IsPostBack)
{
//generate clienttoken from braintree sdk
clientToken = gateway.ClientToken.generate();
}
else
{
var paymentnonce = Request.Form["paymentmethodnonce"];
}
}
}
Full disclosure: I work at Braintree. If you have any further questions, feel free to contact support.
The callback that you pass to hostedFieldsInstance.tokenize uses a css selector to find an element with ID paymentmethodnonce and store the generated nonce inside of it. However, there's no element with that ID in the HTML that you submitted. Based on the HTML you've shared, that call should fail, and your subsequent attempt to retrieve paymentmethodnonce using Request.Form will also fail.
You should be able to solve this by adding a hidden input element to your form with the id paymentmethodnonce.
<input type="hidden" id="paymentmethodnonce" />
This will give your tokenize callback a place to put the nonce, and it will make the nonce part of the form, which should allow your Request.Form to retrieve it successfully.

Ember loading template multiple times and error

I've got an issue where it looks like Ember (1.6.0-beta.4) is attempting to load the same view a second time instead of transitioning to a different view.
The app has a login view and then the main page view. The login view loads great. No issues there. The user enters their creds and hits login. When a successful response comes back, the app transitions to the main page (route is updated as it should be).
But rather than rendering the main page, it renders the login page and the main page stacked together. In the console, there's an error: "Uncaught Error: Assertion Failed: Attempted to register a view with an id already in use: userName"
The only view that has an element with an id of 'userName' is the login view, which leads me to believe it is trying to render the login page a second time, (which is not what I want).
Ember inspector doesn't show anything out of place. When I refresh the main page, the error goes away.
Here are the relevant parts of my app (copied and pasted from a series of js files, I tried to keep things organized as best i could)
my templates:
<script type="text/x-handlebars">
{{#if loggedIn}}
<nav>
<img id="navLogo" src="images/ExsellsiorMAnagerLogo.png" />
<!--<div class="pull-right">Hello {{FirstName}}!</div>-->
</nav>
{{outlet}}
{{else}}
{{outlet}}
{{/if}}
</script>
<script type="text/x-handlebars" id="manifests">
<div class="container-fluid">
<div class="row">
{{render 'filter' model}}
<div id="library" class="col-md-3 left-column"><h2>Library</h2></div>
<div id="stage" class="col-md-7 bg-danger"><h2>Stage</h2></div>
</div>
</div>
</script>
<script type="text/x-handlebars" id="login">
<div class="container">
<form id="login-form" role="form" class="form-horizontal" {{action login on="submit"}}>
<div class="form-group">
<img src="images/ExsellsiorMAnagerLogo.png" alt="Exsellsior Manager Logo" />
</div>
<div class="form-group">
<label for="userName" class="control-label hidden">User Name</label>
{{input id="userName" type="text" class="form-control" placeholder="User Name" value=userName }}
</div>
<div class="form-group">
<label for="pwd" class="control-label hidden">Password</label>
{{input id="pwd" type="password" class="form-control" placeholder="Password" value=password}}
</div>
<div class="form-group">
{{#if inProcess}}
<button id="loginBtn" class="btn btn-primary has-spinner spinner-active" type="submit">
Login<span class="spinner"><i class="icon-primary-spinner"></i></span>
</button>
{{else}}
<button id="loginBtn" class="btn btn-primary has-spinner" type="submit">
Login<span class="spinner"><i class="icon-primary-spinner"></i></span>
</button>
{{/if}}
</div>
{{#if invalidLogin}}
<div id="failure-message" class="form-group has-error bg-danger">
<span class="text-danger">Invalid username or password</span>
</div>
{{/if}}
</form>
</div>
</script>
controllers:
app.ApplicationController = Em.Controller.extend({
needs: ['login'],
loggedIn: false,
tokenChanged: function() {
var self = this,
login = self.get('controllers.login');
if (login.get('token')) {
this.set('loggedIn', true)
} else {
this.set('loggedIn', false)
}
},
userInfoChanged: function () {
var self = this,
login = self.get('controllers.login');
if (login.get('userInfo')) {
this.setProperties(login.get('userInfo'));
}
},
setState: function () {
var self = this;
var login = self.get('controllers.login');
login.addObserver('token', self, self.tokenChanged);
login.addObserver('userInfo', self, self.userInfoChanged);
if (login.get('token')) {
this.set('loggedIn', true);
this.setProperties(login.get('userInfo'));
this.transitionToRoute('manifests');
} else {
this.set('loggedIn', false);
this.transitionToRoute('login');
}
}
});
app.LoginController = Em.Controller.extend({
// resets login info so previous info is not stored
reset: function () {
var self = this;
self.setProperties({
userName: "",
password: "",
invalidLogin: false
});
},
// define dependency on application controller
//needs: ['application'],
// initializes with user token, if one exists
token: localStorage.getItem("token"),
userInfo: JSON.parse(localStorage.getItem("userInfo")),
// monitors if token changes and updates local storage if so
tokenChanged: function() {
localStorage.setItem("token", this.get('token'));
}.observes('token'),
userInfoChanged: function () {
localStorage.setItem("userInfo", JSON.stringify(this.get('userInfo')))
}.observes('userInfo'),
actions: {
// action to fire when user attempts to log in
login: function () {
var self = this;
if (self.get('inProcess')) {
return;
}
self.set('inProcess', true);
// function.bind() specifies the context the function will be executed in
// (the 'this' object within the function)
// login returns the promise from an AJAX call
return app.util.login(self.get('userName'), self.get('password'))
.then(loginSuccess.bind(self), loginFailure.bind(self));
}
}
});
app.FilterController = Em.ObjectController.extend({
showing: true,
actions: {
collapse: function () {
this.set('showing', !this.get('showing'));
}
}
});
Routes:
app.Router.map(function () {
// /login
this.resource('login');
// /manifests
this.resource('manifests',function(){
this.resource('filter');
});
});
app.AuthenticatedRoute = Em.Route.extend({
// checks if we have a token - if not we can assume we're
// not logged in before we make an ajax call
beforeModel: function(transition) {
if (!this.controllerFor('login').get('token')) {
this.redirectToLogin(transition);
}
},
// function to handle re-routing to login screen
redirectToLogin: function(transition) {
var loginController = this.controllerFor('login');
loginController.set('attemptedTransition', transition);
this.transitionTo('login');
},
// reusable function for data requests
executeAjax: function(method, url, data) {
var token = this.controllerFor('login').get('token');
return app.util.executeAjax(method, url, token, data);
},
actions: {
error: function(reason, transition) {
if (reason.status === 401) {
this.redirectToLogin(transition);
} else {
// todo: handle this better
alert('Something went wrong');
}
}
}
});
app.LoginRoute = Em.Route.extend({
// ensures user data is cleared when login page loads/reloads
setupController: function(controller, context) {
controller.reset();
}
});
app.ManifestsRoute = app.AuthenticatedRoute.extend({
model: function () {
return this.executeAjax("GET", "states").then(function (result) {
return {
states: result
}
});
}
});
Comments can't be used in handlebars like this,
<!--<div class="pull-right">Hello {{FirstName}}!</div>-->
They should be wrapped in handlebars:
{{!-- foo --}}
Also your outlet should be out of the scope of the if statement:
{{#if loggedIn}}
<nav>
<img id="navLogo" src="images/ExsellsiorMAnagerLogo.png" />
{{!-- <div class="pull-right">Hello {{FirstName}}!</div> --}}
</nav>
{{/if}}
{{outlet}}

Categories