I am using vuejs 2 and I am having issues with using the Google auth signin.
I successfully setup and got the sign out and user profile functions working using vue:
export default {
data() {
return {
user: null
};
},
methods: {
getUserProfile() {
const profile = gapi.auth2.currentUser.get().getBasicProfile();
console.log(profile.getIdToken());
},
signOut() {
const auth2 = gapi.auth2.getAuthInstance();
auth2.signOut().then(function () {
console.log('user signed out');
});
}
},
};
My main issue here is the onSignIn(googleUser) function from
<div class="g-signin2" data-onsuccess="onSignIn"></div>
The data-onsuccess="onSignIn" is looking for a js function outside the vue instance.
I tried adding the onSignIn(googleUser) function in my HTML file like:
<script>
function onSignIn(googleUser) {
const auth2 = gapi.auth2.init();
if (auth2.isSignedIn.get()) {
const profile = auth2.currentUser.get().getBasicProfile();
console.log(profile.getName());
console.log(googleUser.getAuthResponse().id_token);
console.log(googleUser.getAuthResponse().uid);
console.log(auth2.currentUser.get().getId());
}
}
</script>
This works as expected, but I wanted to know if it would be possible to add this in my vue file instead of a native javascript way, since inside this function, I will be calling other vue methods.
Or is there a way where I could add the onSignIn(googleUser) function in vue and then call it when Google Auth finishes?
The solution here is to use gapi.signin2.render to render the sign-in button inside your component's mounted hook
<template>
<div id="google-signin-btn"></div>
</template>
<script>
export default {
methods: {
onSignIn (user) {
// do stuff, for example
const profile = user.getBasicProfile()
}
},
mounted() {
gapi.signin2.render('google-signin-btn', { // this is the button "id"
onsuccess: this.onSignIn // note, no "()" here
})
}
}
</script>
See https://developers.google.com/identity/sign-in/web/reference#gapisignin2renderid_options
Related
This question already has answers here:
"Uncaught SyntaxError: Cannot use import statement outside a module" when importing ECMAScript 6
(31 answers)
Closed 1 year ago.
I have a javascript function in a separate js file toaster-message.js, the file is in wwwroot/js of ASP.net application, which calls the bootstrap toaster.
toaster-message.js.
showCompleteToast: (message) => {
const toastElm = document.getElementById('#complete-toast');
const toast = new bootstrap.Toast(toastElm)
toast.show();
}
I want to call the showCompleteToast() from my vue instances. I am creating the vue instances with Direct script Include.
I don't want to add any Vue dependency to the function outside the Vue instances. So what is the proper way to call the function in the external js file that is outside the Vue instances?
#section scripts {
<script>
const app = new Vue({
el: "#app",
data() {
return {
}
},
methods: {
showToast: function(){
//I want to call the show toast from here
},
submit: async function () {
try {
this.showToast();
} catch (error) {
console.log(error)
}
}
}
});
</script>
}
When i try to import using:
import { showCompleteToast } from "~/lib/js/toater-message.js"
while using:
export default {
showCompleteToast: (message) => {
const toastElm = document.getElementById('#complete-toast');
const toast = new bootstrap.Toast(toastElm)
toast.show();
},
// ... other methods here
};
I get the error as:
“Uncaught SyntaxError: Cannot use import statement outside a module”
I tried to to import using:
<script type="module">
import { showCompleteToast } from "../../wwwroot/js/toaster-message.js"
alert(showCompleteToast)
</script>
This gave the error as:
GET https://localhost:44307/wwwroot/js/toaster-message.js net::ERR_ABORTED 404
I'm not very familiar with php but typically you can import JavaScript files and then work with their contents. The only requirement is that the imported files need to have exporting defined.
// toaster-message.js
export default {
showCompleteToast: (message) => {
const toastElm = document.getElementById('#complete-toast');
const toast = new bootstrap.Toast(toastElm)
toast.show();
},
// ... other methods here
};
Then pull it into your Vue file like this:
#section scripts {
<script>
import { showCompleteToast } from "..path/to/toaster-message.js"
const app = new Vue({
el: "#app",
data() {
return {
}
},
methods: {
showToast: function(){
//I want to call the show toast from here
showCompleteToast();
},
submit: async function () {
try {
this.showToast();
} catch (error) {
console.log(error)
}
}
}
});
</script>
}
I have a VueJS Program where I want to provide a login. Thus this login is used one multiple platforms, it is loaded via an external server (See: mounted). It is loaded, puts elements into the mainlogin-div creating a login view and when the user clicks Login it performs a http login request to another server. When the login is successful, the external script calls done(result) or error(result) whether the login was a success or not.
But now of course how can I go back to calling Vue-stuff from there? I cant just do like this.$router.push("/coolPath") or call a defined method like loggedIn to make a toast or what not... How is this implemented?
<template>
<div id="main">
<div id="mainlogin"></div>
<script type="application/javascript">
function done(result){
console.log(result);
loggedIn(result, true)
}
function error(result) {
console.log(result)
loggedIn(result, false)
}
</script>
</div>
</template>
<script>
const Toast = require("#/toast/toast")
export default {
name: "Login",
components: {},
data() {
return {
isAuthenticated: false
}
},
beforeMount() {
let loginScript = document.createElement('script')
loginScript .setAttribute('src', 'http://**.***.***.***/index_krass.js')
document.body.appendChild(loginScript )
},
methods: {
loggedIn: function (result, success){
Toast.toast(result.message, success)
}
}
}
</script>
<style>
...
</style>
Error is always "this." is not defined or loggedIn(...) is not defined...
Maybe its some race condition where VueJS needs to be loaded first or the other way around?
Instead of the <script> block in the template, just set the global functions up on window as arrow functions to capture the Vue instance context:
export default {
beforeMount() {
window.done = result => this.loggedIn(result, true)
window.error = result => this.loggedIn(result, false)
let loginScript = document.createElement("script")
loginScript.setAttribute("src", ".../index_krass.js")
document.body.appendChild(loginScript)
},
destroyed() {
window.done = window.error = undefined
},
}
demo
I am implementing Twitter authentication using FirebaseUI in my Vue.js app.
While I can successfully authenticate the user, I can't figure out how to store info from the AuthResult object.
In my parent component (App.vue), I listen for the onAuthStateChanged event to save the user details. This works well, but the user object doesn't contain API credentials returned by Twitter.
firebase.auth().onAuthStateChanged((user) => {
if (user) {
this.user = user
this.$router.push('/user')
} else {
this.$router.push('/login')
}
})
Those credentials are contained in the firebaseui.auth.AuthResult object, which is accessible in the FirebaseUI callback named signInSuccessWithAuthResult.
The problem I am facing is that I cannot call Vue.js functions from within this callback - I can't modify data using this.foo, I can't emit an event either with this.$emit. I can console.log() the authResult object, but that's about it.
Q: How can I save the authResult object in my Vue app?
For clarity, here is my child Login component (template simplified):
<template>
<div>
<div id="firebaseui-auth-container"></div>
</div>
</template>
<script>
import firebase from 'firebase'
import * as firebaseui from 'firebaseui'
export default {
name: 'Login',
data () {
return {
foo: ''
}
},
mounted () {
var uiConfig = {
signInOptions: [
firebase.auth.TwitterAuthProvider.PROVIDER_ID
],
signInFlow: 'popup',
callbacks: {
signInSuccessWithAuthResult: function (authResult) {
// this.$emit('updateAuthResult', authResult)
// this.foo = 'bar'
console.log(authResult)
return true
}
}
}
var ui = new firebaseui.auth.AuthUI(firebase.auth())
ui.start('#firebaseui-auth-container', uiConfig)
}
}
</script>
Isn't it a problem of context? See When to Use vm. or this. in Vue.js
What happens if you do:
mounted () {
var vm = this
var uiConfig = {
signInOptions: [
firebase.auth.TwitterAuthProvider.PROVIDER_ID
],
signInFlow: 'popup',
callbacks: {
signInSuccessWithAuthResult: function (authResult) {
vm.$emit('updateAuthResult', authResult)
vm.foo = 'bar'
console.log(authResult)
return true
}
}
}
var ui = new firebaseui.auth.AuthUI(firebase.auth())
ui.start('#firebaseui-auth-container', uiConfig)
}
I think you can use an arrow function to resolve this problem
mounted () {
var uiConfig = {
signInOptions: [
firebase.auth.TwitterAuthProvider.PROVIDER_ID
],
signInFlow: 'popup',
callbacks: {
signInSuccessWithAuthResult: (authResult) => {
this.$emit('updateAuthResult', authResult)
console.log(authResult)
return true
}
}
}
var ui = new firebaseui.auth.AuthUI(firebase.auth())
ui.start('#firebaseui-auth-container', uiConfig)
}
I have a block of html that is sent down from the server, and I want to call a method or function from links embedded in that html.
in my .vue file, the html is being displayed like so:
<template>
<div v-html="myhtml"></div>
</template>
<script>
import axios from 'axios'
export default {
data () {
return {
myhtml: null
}
},
created () {
this.refreshHTML()
},
methods: {
refreshHTML () {
axios.get()// get my html
this.myhtml = response.data
},
myFunction () {
//do my function stuff here...
}
}
}
</script>
And what I would like to do in the html that is fetched is attach an onclick event that fires my function like so:
<a href="myurl" onclick='event.preventDefault();myFunction(this.href);'>link</a>
But when I try, I get:
ReferenceError: Can't find variable: myFunction
This screams bad practice all over the place.
If I HAD to do this:
I'd add the function to the global scope (bad practice), and call it from the html event handler (also bad practice):
<template>
<div v-html="myhtml"></div>
</template>
<script>
import axios from 'axios'
export default {
data () {
return {
myhtml: null
}
},
created () {
this.refreshHTML();
window.myFunction = this.myFunction.bind(this);
},
methods: {
refreshHTML () {
axios.get()// get my html
this.myhtml = response.data
},
myFunction () {
//do my function stuff here...
}
}
}
</script>
Consider converting the html into vue components and use them instead.
I'm developing a Vue.js app and I'm trying to make a log in system using multiple components.
on my App.vue component (which is the "primary" component and has the nav-bar) there is this button:
<a class="nav-item" v-link="'login'" v-if="!user.authenticated">Login</a>
...
import auth from '../auth'
export default {
data(){
return{
user = auth.user
}
}
}
In one other file (/auth/index.js) I define the "auth" methods as such:
...
user: {
authenticated: false
},
login(email, password) {
axios.post(LOGIN_URL, {
email,
password
}).then((response) => {
this.user.authenticated = true;
this.user = response.data;
router.go('/home');
})
.catch((error)=>{
console.log(error);
});
}
And then I have another component name Login.vue that handles the view for the login template and calls the "auth.login" method with the required params.
The thing is that I want to update the user from App.vue with the value from auth.user AFTER he logs in. How should I do that? Do I have to manage the v-on:click and v-link priorities and come up with a new method?
EDIT:
I'm also trying to use the beforeRouteEnter method by I am not being successful
I managed to find a solution adding this:
watch: {
$route () {
this.user = auth.user
}
},
Following the documentation here