vuefire binding broke after using firebase auth & router - firebase

I've a simple vuejs app, connected to firebase, the v-for in the child component was working perfectly until I implemented authentication with firebase and the vue router.
Now its broken :(
Authentication happens fine, but the items from the query are not being there anymore (undefined).
Firebase credentials are good and the database herself has data on the selected path.
this is main.js
import 'onsenui';
import Vue from 'vue';
import VueOnsen from 'vue-onsenui';
import VueFire from 'vuefire';
import VueRouter from 'vue-router'
import firebaseui from 'firebaseui';
import router from './router'
import {connection} from './firebaseconfig';
require('onsenui/css-components-src/src/onsen-css-components.css');
require('onsenui/css/onsenui.css');
require('firebaseui/dist/firebaseui.css');
import App from './App.vue';
Vue.use(VueOnsen);
Vue.use(VueFire);
Vue.use(VueRouter);
var app = new Vue({
router,
created() {
connection.auth().onAuthStateChanged((user) => {
if(user) {
this.$router.push('/home')
} else {
this.$router.push('/auth')
}
});
} ,
el: '#app',
template: '<app></app>',
components:{
App
} ,
render: h => h(App)
});
App.vue
<template>
<router-view></router-view>
</template>
<script>
import auth from './components/auth'
import dashboard from './components/dashboard'
import home from './components/homePage'
import stores from './components/storesPage'
import social from './components/socialPage'
import settings from './components/settingsPage'
export default {
data() {
return {
currentPage: 'auth',
// pages: ['home', 'stores', 'settings' , 'social'],
pages: {
'dashboard' :
{ 'name' : 'dashboard' , 'icon' : 'md-view-dashboard' } ,
'home' :
{ 'name' : 'home' , 'icon' : 'md-view-home' } ,
'Stores' :
{ 'name' : 'stores' , 'icon' : 'md-store' } ,
'Social' :
{ 'name' : 'social' , 'icon' : 'md-share' } ,
'account' :
{ 'name' : 'account' , 'icon' : 'md-account-o' } ,
'auth' :
{ 'name' : 'auth' , 'icon' : 'md-settings' } ,
},
openSide: false
};
},
components: {
auth,
dashboard,
home,
stores,
settings ,
social
}
}
</script>
Fire base config :
import firebase from 'firebase';
const config = {
apiKey: "xxxxxxxxxx",
authDomain: "xxx",
databaseURL: "xxx",
projectId: "yyyyy",
storageBucket: "yyyyyyy",
messagingSenderId: "yyyyy"
};
export const FireBconfig = config;
export const connection = firebase.initializeApp(config);
export const db = connection.database();
auth.vue
<template lang="html">
<div id="firebaseui-auth-container">
</div>
</template>
<script>
import firebase from 'firebase';
import firebaseui from 'firebaseui'
import {FireBconfig} from '../firebaseconfig';
export default {
name: 'auth',
mounted() {
var uiConfig = {
signInSuccessUrl: '/success',
signInOptions: [
firebase.auth.GoogleAuthProvider.PROVIDER_ID,
firebase.auth.EmailAuthProvider.PROVIDER_ID
]
};
var ui = new firebaseui.auth.AuthUI(firebase.auth());
ui.start('#firebaseui-auth-container', uiConfig);
},
}
</script>
and finally the child component displaying on successful auth and pulling data from the firebase path
<template>
<v-ons-page style="background-color:grey">
<custom-toolbar class="topbarback" :title="'Home'" :action="toggleMenu">
</custom-toolbar>
<v-ons-pull-hook :action="loadItem" #changestate="state = $event.state">
<span v-show="state === 'initial'"> Pull to refresh </span>
<span v-show="state === 'preaction'"> Release </span>
<span v-show="state === 'action'"> <v-ons-progress-bar indeterminate></v-ons-progress-bar> </span>
</v-ons-pull-hook>
<v-ons-row >
<v-ons-col v-bind:key="item" v-for="item in items" width="33%">
<div style="padding:5px;margin: 0px;border:solid 2px #E4E4E4;height:240px;vertical-align:middle;display:table-cell;background-color:#FFF;position: relative;">
<div style="text-align:center">
<ons-input #change="checkboxclick" :input-id="item.ItemID" v-model="selected" style=" position: absolute; top: 10px; right: 10px;" type="checkbox" ></ons-input>
<label :for="item.ItemID">
<span class="price">{{item.CurrentPriceAmount}} €</span>
<span class="watchers">10</span>
<img tappable style="width:85%;max-height:85%" class="item-thum" v-bind:src="item. PictureDetailsGalleryURL" />
</label>
</div>
<div class="item-title"> <span style="font-size:9px;background-color:#FFF">{{item.title}}</ span><br /><br /></div>
</div>
</v-ons-col>
</v-ons-row>
<v-ons-speed-dial position="bottom right" direction="up"
:visible="spdVisible"
:open.sync="spdOpen"
>
<v-ons-fab :style="spdStyle">
<v-ons-icon style="font-size:8px" icon="md-format-valign-top"><span style=" font-size:12px;font-family: 'Open Sans', sans-serif;">{{counter}}</span></v-ons-icon>
</v-ons-fab>
<v-ons-speed-dial-item v-for="(icon, name) in shareItems"
:style="spdStyle"
#click="$ons.notification.confirm(`Share on ${name}?`)"
>
<v-ons-icon :icon="icon"></v-ons-icon>
</v-ons-speed-dial-item>
</v-ons-speed-dial>
</v-ons-page>
</template>
<script>
import customToolbar from './toolbarHome'
import {db} from '../firebaseconfig';
export default {
data :
function() {
return {
spdVisible: false,
spdOpen: false,
spdStyle: {
backgroundColor: this.$ons.platform.isIOS() ? '#4282cc' : null
} ,
items : [1,2,3] ,
counter : 0 ,
selectedItems : [] ,
state: 'initial',
selected : [],
shareItems: {
'With Relist': 'md-swap-alt' ,
'Facebook': 'md-arrow-split',
}
}
},
firebase: {
items : {
source: db.ref('users/buisine/stores/ebay/red/items')
}
},
props: ['toggleMenu' , 'itemsRef'],
components: { customToolbar } ,
methods: {
checkboxclick(event) {
if(event.target.checked===true)
{
this.counter++;
this.selectedItems.push(event.target.id);
}
else
{
this.selectedItems.splice( this.selectedItems.indexOf(event.target.id) , 1);
this.counter--;
}
},
loadItem(done) {
setTimeout(() => {
this.items = [...this.items, this.items.length + 1];
done();
}, 1500);
},
}
}
</script>
Tried different code on the firebase object that should return the data, nothing worked.

Well, tried on clean blank vuejs project, failed again.
BUT worked again by supressing all Users in the authentication tab in firebase console !!

Related

Nuxt3 can't import component in tests

I'm trying to run a component unit test on Nuxt 3 but I get an error telling me that the component cannot be found..
FAIL test/components/button.test.ts [ test/components/button.test.ts ]
Error: Failed to resolve import "#/components/Texts/Button/ButtonText.vue" from "components\Button\Button.vue". Does the file exist?
button.spec.ts
import {test, expect} from 'vitest';
import {mount} from '#vue/test-utils';
import Button from "../../components/Button/Button.vue";
test('Button Component', async () => {
const button = mount(Button, {
props: {
text: 'My Test Button'
}
});
expect(button.text()).toEqual('My Test Button');
});
Button.vue
<template>
<div class="Button">
<slot name="left" />
<ButtonText :text="text" />
<slot name="right" />
</div>
</template>
<script lang="ts">
export default {
name: 'Button',
components: {ButtonText},
props: {
// Text to display in the button
text: {
type: String as () => string,
default: 'Button',
required: true,
},
}
}
</script>
any ideas ?
Assuming, that #/components/Texts/Button/ButtonText.vue actually exists, a solution to your problem might be adding aliases to your ./vitest.config.ts like that:
// vitest.config.ts
import { defineConfig } from 'vite'
import { aliases } from './aliases'
export default defineConfig({
resolve: { aliases },
// ... further settings
})
// aliases.ts
import { resolve } from 'path';
const r = (p: string) => resolve(__dirname, p);
export const alias: Record<string, string> = {
'~~': r('.'),
'~~/': r('./'),
'##': r('.'),
'##/': r('./'),
// ... other aliases
};

How do I display a route parameter (Vue / Firebase)

I'm creating a blog with free sewing patterns as content. I'm using route parameters to receive each blog individually. However, I'm getting a blank page when trying to retrieve its data from firebase firestore. Please help.
The blog's id appears on my address bar:
http://localhost:8080/#/admin/single-pattern/4LIS362IEWa7RKEv79g8
But it renders a blank page. I cant see my blog content.
This is my route path code. I've added a parameter of :id in my singlepattern. The SinglePattern component is where I will get the individual blog's data:
{
path: "/admin",
name: "admin",
component: Admin,
meta: {
auth: true,
},
children: [
{
path: "dashboard",
name: "dashboard",
component: Dashboard,
},
{
path: "manage-patterns",
name: "manage-patterns",
component: ManagePatterns,
},
{
path: "single-pattern/:id",
name: "single-pattern",
component: SinglePattern,
},
],
},
Here is my "ListPattern" component's code. ListPattern is where all my sewing blogs are displayed.
<template>
<div class="list-blogs">
<h1>LIST BLOG TITLES</h1>
<br />
<input type="text" v-model="search" placeholder="search blogs" />
<div
class="blog-cover"
v-for="pattern in filteredPatterns"
:key="pattern.id"
>
<div>
<router-link v-bind:to="'/admin/single-pattern/' + pattern.id">
<h3 style="cursor: pointer" v-rainbow>
{{ pattern.title | uppercase }}
</h3></router-link
>
</div>
<p
:style="'background-color: var(--lightgrey)'"
:inner-html.prop="pattern.description | snippet"
></p>
</div>
</div>
</template>
<script>
import firebase from "firebase";
import searchMixin from "../mixins/searchMixin";
// Basic Use - Covers most scenarios
import { VueEditor } from "vue2-editor";
import Quill from "quill";
const AlignStyle = Quill.import("attributors/style/align");
Quill.register(AlignStyle, true);
// import $ from "jquery";
import Swal from "sweetalert2";
window.Swal = Swal;
const Toast = Swal.mixin({
toast: true,
position: "top-end",
showConfirmButton: false,
timer: 3000,
});
window.Toast = Toast;
export default {
name: "ManagePatterns",
components: { VueEditor },
data() {
return {
patterns: [],
pattern: {
title: null,
description: null,
image: null,
},
search: "",
};
},
firestore() {
return {
patterns: firebase.firestore().collection("free-patterns"),
};
},
computed: {},
},
};
</script>
And this is my 'SinglePattern' component where the clicked blog/pattern is displayed.
<template>
<div class="single-pattern">
<div class="blog-cover">
<div>
</div>
<div v-if="pattern">
<h3 style="cursor: pointer">
{{ pattern.title }}
</h3>
<div v-if="pattern.description">
<p
:style="'background-color: var(--lightgrey)'"
:inner-html.prop="pattern.description"
></p>
</div>
</div>
</div>
</div>
</template>
<script>
import firebase from "firebase";
import searchMixin from "../../mixins/searchMixin";
export default {
data() {
return {
id: this.$route.params.id,
patterns: [],
pattern: {
title: null,
description: null,
image: null,
},
};
},
firestore() {
return {
patterns: firebase.firestore().collection("free-patterns"),
};
},
mixins: [searchMixin],
created() {
console.log(this.$route.params.id);
var pat = this;
firebase
.firestore()
.collection("free-patterns")
.doc(this.$route.params.id)
.get()
.then(function(doc) {
if (doc.exists) {
pat.pattern = doc.data().pattern;
} else {
console.log("no such doc");
}
});
},
methods: {},
};
</script>
It works. I just had to change the code in my created() hook in 'SingePattern' component.
created() {
console.log(this.$route.params.id);
var docRef = firebase
.firestore()
.collection("free-patterns")
.doc(this.$route.params.id);
docRef
.get()
.then((doc) => {
if (doc.exists) {
this.pattern = doc.data();
} else {
// doc.data() will be undefined in this case
console.log("No such document!");
}
})
.catch((error) => {
console.log("Error getting document:", error);
});

action not found in Vuex store

I'm following a course here:
https://thinkster.io/tutorials/nuxt-js-project/adding-authentication
I am working on adding authentication to my app and have login/logout buttons that partially work with firebase authentication. I can log in fine, but the issue is that when I'm logged in, the action in my Vuex store doesn't seem to run, therefore leaving the user logged in and the state not updating to display the logout button.
default.vue
<template>
<v-app>
<v-navigation-drawer
v-model="drawer"
:mini-variant="miniVariant"
:clipped="clipped"
fixed
app
>
<v-list>
<v-list-item
v-for="(item, i) in items"
:key="i"
:to="item.to"
router
exact
>
<v-list-item-action>
<v-icon>{{ item.icon }}</v-icon>
</v-list-item-action>
<v-list-item-content>
<v-list-item-title v-text="item.title" />
</v-list-item-content>
</v-list-item>
<button v-if="!mySession" #click="login">Login</button>
<button v-else #click="logout">Logout</button>
</v-list>
</v-navigation-drawer>
<!-- <v-toolbar fixed app :clipped-left="clipped">
<v-toolbar-side-icon #click="drawer = !drawer"></v-toolbar-side-icon>
<v-tool-bar-title v-text="title"></v-tool-bar-title>
<v-spacer></v-spacer>
<v-toolbar-items>
<v-btn #click="login">Login</v-btn>
<v-btn #click="logout">Logout</v-btn>
</v-toolbar-items>
</v-toolbar> -->
<v-app-bar
:clipped-left="clipped"
fixed
app
>
<v-app-bar-nav-icon #click.stop="drawer = !drawer" />
<v-btn
icon
#click.stop="clipped = !clipped"
>
<v-icon>mdi-application</v-icon>
</v-btn>
<v-btn
icon
#click.stop="fixed = !fixed"
>
<v-icon>mdi-minus</v-icon>
</v-btn>
<v-toolbar-title v-text="title" />
<v-spacer />
</v-app-bar>
<v-content>
<v-container>
<nuxt />
</v-container>
</v-content>
<v-navigation-drawer
v-model="rightDrawer"
:right="right"
temporary
fixed
>
<v-list>
<v-list-item #click.native="right = !right">
<v-list-item-action>
<v-icon light>
mdi-repeat
</v-icon>
</v-list-item-action>
<v-list-item-title>Switch drawer (click me)</v-list-item-title>
</v-list-item>
</v-list>
</v-navigation-drawer>
<v-footer
:fixed="fixed"
app
>
<span>© 2019</span>
</v-footer>
</v-app>
</template>
<script>
import {db} from '#/plugins/firebase'
import firebase from 'firebase/app'
import 'firebase/auth'
export default {
created() {
this.$store.dispatch('setSession');
},
data () {
return {
clipped: false,
drawer: false,
fixed: false,
items: [
{
icon: 'mdi-apps',
title: 'Welcome',
to: '/'
},
{
icon: 'cart',
title: 'Checkout',
to: '/checkout'
}
],
miniVariant: false,
right: true,
rightDrawer: false,
title: 'Vuetify.js'
}
},
methods: {
login() {
console.log('login');
let provider = new firebase.auth.GoogleAuthProvider();
firebase.auth()
.signInWithPopup(provider)
.then(function(result) {
console.log('signed in');
})
.catch(function(error) {
console.log(error);
})
},
logout() {
console.log('logout');
firebase.auth()
.signOut()
.then(() => {
console.log('sign out')
}).catch((error) => {
console.log(error)
})
}
},
computed: {
mySession() {
return this.$store.getters.session;
}
}
}
</script>
store/index.js
import Vuex from 'vuex'
import firebase from 'firebase/app'
import 'firebase/auth'
const createStore = () => {
return new Vuex.Store({
state: {
session: false
},
mutations: {
SET_SESSION(state, session) {
state.session = session;
}
},
getters: {
session: state => state.session
},
actions: {
setSession({commit}) {
firebase.auth().onAuthStateChanged(user => {
console.log(user);
console.log('change');
commit('SET_SESSION', user || false);
})
}
}
})
}
export default createStore
in console I am getting an error message that says:
"[vuex] unknown action type: setSession"
To reiterate, I can login using Google oauth, but when logged in, the state does not change and the logout button does not appear.
Thanks for the help!
Update:
Well now I'm extra confused. I did push updates 15 mins ago but for some reason my store/index.js file is outdated and isn't updating/saving? I have no idea what I'm doing wrong.
When looking at my store/index.js file on Github, it shows the default template:
https://github.com/SIeep/US-kratom/blob/master/US-Kratom/store/index.js
But what I have, and what was just copied from the course I'm taking is:
import Vuex from 'vuex';
import firebase from 'firebase/app';
import 'firebase/auth';
const createStore = () => {
return new Vuex.Store({
state: {
session: false,
products: []
},
mutations: {
SET_SESSION(state, session) {
state.session = session;
},
SET_PRODUCT(state, product) {
state.products = product;
}
},
getters: {
session: state => state.session,
products: state => state.products
},
actions: {
setSession({ commit }) {
firebase.auth().onAuthStateChanged(user => {
commit('SET_SESSION', user || false);
});
},
setProduct({ commit }, products) {
commit('SET_PRODUCT', products);
}
}
});
};
export default createStore;
I am saving the file and everything but it's not updating on Github which is obviously the issue with my app as well.
Erik from Thinkster.io ended up fixing the code for me. Update is here:
[https://github.com/SIeep/US-kratom/commit/bd55deacadfc065edc7df9c1365ae832a32b9b43][1]

Vue.js / Firebase and Vuefire - Read and update a single object

I've been trying to set up a simple app to test some Vue.js features and I've been finding here and there some intersting tutorials about basic CRUD implementation.
I've been stuck on something a little different since a few days, here's a simple description of what I try to achieve :
Set up a home page that displays first and last name.
Store first and last name in firebase as strings
Simply display the two strings on screen
later allow the logged-in user to edit the string (not part of my problem here but relevant to explain why I need the two fields to be stored in Firebase)
I've already worked on a small architecture with login management, different menus for logged in/out states, things like that.
So I already set up that in Firebase :
Firebase configuration
Then here my core files :
main.js
// The Vue build version to load with the `import` command
// (runtime-only or standalone) has been set in webpack.base.conf with an alias.
import Vue from 'vue'
import App from './App'
import router from './router'
import firebase from 'firebase'
import VueFire from 'vuefire'
import { store } from './store/store'
let app
let config = {
apiKey: '######',
authDomain: '######',
databaseURL: '######',
projectId: '######',
storageBucket: '######',
messaginSenderId: '######'
}
firebase.initializeApp(config)
firebase.auth().onAuthStateChanged(function (user) {
if (!app) {
/* eslint-disable no-new */
app = new Vue({
el: '#app',
store: store,
router,
template: '<App/>',
components: { App }
})
}
})
export const db = firebase.database()
export const homeContent = db.ref('homeContent')
Vue.config.productionTip = false
Index.js
import Vue from 'vue'
import Router from 'vue-router'
import HelloWorld from '#/components/HelloWorld'
import Test from '#/components/Test'
import Login from '#/components/Login'
import SignUp from '#/components/SignUp'
import firebase from 'firebase'
import VueFire from 'vuefire'
Vue.use(Router)
Vue.use(VueFire)
let router = new Router({
routes: [
{
path: '*',
redirect: '/login'
},
{
path: '/',
redirect: '/login'
},
{
path: '/login',
name: 'Login',
component: Login
},
{
path: '/test',
name: 'Test',
component: Test,
meta: {
requiresAuth: true
}
},
{
path: '/sign-up',
name: 'SignUp',
component: SignUp
},
{
path: '/hello-world',
name: 'HelloWorld',
component: HelloWorld,
meta: {
requiresAuth: true
}
}
]
})
router.beforeEach((to, from, next) => {
let currentUser = firebase.auth().currentUser
let requiresAuth = to.matched.some(record => record.meta.requiresAuth)
if (requiresAuth && !currentUser) next('/login')
else if (!requiresAuth && currentUser) next()
else next()
})
export default router
App.vue
<template>
<div id="app">
<div v-if="user">Logged in</div>
<div v-else>NOT logged in</div>
<Navigation></Navigation>
<button id="btLogout" v-if="user" v-on:click="logout">Déconnexion</button>
<img class="logo" src="./assets/logo.png">
<router-view/>
</div>
</template>
<script>
// Register Navbar component
import Navigation from './components/Nav.vue'
import firebase from 'firebase'
export default {
computed: {
user () {
return this.$store.getters.getUser
}
},
components: {
'Navigation': Navigation
},
methods: {
logout: function () {
firebase.auth().signOut().then(() => {
this.$store.dispatch('clearUser')
this.$router.replace('login')
})
},
setUser: function () {
this.$store.dispatch('setUser')
}
},
created () {
// when the app is created run the set user method
// this uses Vuex to check if a user is signed in
// check out mutations in the store.js file
this.setUser()
}
}
</script>
<style>
#app {
font-family: 'Avenir', Helvetica, Arial, sans-serif;
-webkit-font-smoothing: antialiased;
-moz-osx-font-smoothing: grayscale;
text-align: center;
color: #2c3e50;
margin-top: 60px;
}
.logo {
width: 50px;
height: auto;
clear: both;
display: block;
margin: 30px auto 0;
}
#btLogout {
clear: both;
display: inline-block;
}
</style>
Test.vue
<template>
<div class="homeScreen">
<p v-bind:key="homeContent['.key']" v-for="firstName of homeContent">{{ homeContent.firstName }}</p>
<p v-bind:key="homeContent['.key']" v-for="lastName of homeContent">{{ homeContent.lastName }}</p>
<img src="../assets/annonce_motw.jpg">
</div>
</template>
<!-- Javascript -->
<script>
import firebase from 'firebase'
import db from "../main"
export default {
data () {
return {
db: ''
}
},
firebase: {
homeContent: {
source: db.ref('homeContent'),
asObject: true
}
},
methods: {
setHomeName (key) {
// homeName.child(key).update({ edit: true })
}
},
created () {
}
}
</script>
<!-- SASS styling -->
<style scoped>
</style>
So here I am. The part where I'm stuck is that everytime I try to add in Test.vue the line db.ref('homeContent') the console returns that db is undefined.
I also can't figure how to simply output the stored strings after resolving the console problem.
So what did I do wrong? :D
Thanks and advance for every piece of help you'll bring! Cheers!
The line
export const db = firebase.database()
gets executed before firebase.initializeApp(config) has finished executing, so it will be undefined.
One way to solve this is to put the initialized Firebase object on the Vue prototype:
Vue.prototype.$firebase = Firebase.initializeApp(config)
Then, inside any of your components, such as Test.vue, you can refer to the Firebase object like this:
firebase: {
homeContent: {
source: this.$firebase.database().ref('homeContent'),
asObject: true
}
},
One caveat: This only works if you create the Vue app after you know Firebase has finished initializing. You did this correctly by putting the new Vue() statement inside firebase.auth().onAuthStateChanged() in main.js, so you will be guaranteed to have an initialized Firebase object available to you at this.$firebase in any of your components.

vue router error with firebase auth

I tried to auth using vue.js and firebase.
and error occurs router.beforeEach function,
Anyone has any idea why it might happen?
console error
vue-router.esm.js?fe87:16 [vue-router] uncaught error during route navigation:
warn # vue-router.esm.js?fe87:16
abort # vue-router.esm.js?fe87:1904
iterator # vue-router.esm.js?fe87:1968
step # vue-router.esm.js?fe87:1717
runQueue # vue-router.esm.js?fe87:1725
confirmTransition # vue-router.esm.js?fe87:1972
transitionTo # vue-router.esm.js?fe87:1874
push # vue-router.esm.js?fe87:2181
(anonymous) # vue-router.esm.js?fe87:1960
(anonymous) # index.js?3672:44
router/index.js
import Vue from 'vue'
import Router from 'vue-router'
import addPost from '#/components/addPost'
import showPost from '#/components/showPost'
import Login from '#/components/Login'
import SignUp from '#/components/SignUp'
import firebase from 'firebase'
Vue.use(Router)
const router = new Router({
mode: 'history',
routes: [
{
path: '/',
name: 'app',
component: showPost
},
{
path: '/add',
component: addPost,
meta: {
requiresAuth: true
}
},
{
path: '/login',
name: 'Login',
component: Login
},
{
path: '/signup',
name: 'SignUp',
component: SignUp
}
]
})
router.beforeEach((to, from, next) => {
let currentUser = firebase.auth().currentUser;
let requiresAuth = to.matched.some(record => record.meta.requiresAuth);
if (requiresAuth && !currentUser) next('/login')
else if (!requiresAuth && currentUser) next('/')
else next()
})
export default router
main.js
import Vue from 'vue'
import App from './App'
import router from './router'
import VueFire from 'vuefire'
import firebase from 'firebase'
Vue.use(VueFire)
Vue.config.productionTip = false
let app;
firebase.auth().onAuthStateChanged(function(user) {
if(!app) {
app = new Vue({
el: '#app',
router,
template: '<App/>',
components: { App }
})
}
})
App.vue
<template>
<div id="app">
<app-header></app-header>
<router-view></router-view>
<button #click="logout">Logout</button>
</div>
</template>
<script>
import header from './components/header'
import firebase from 'firebase'
export default {
name: 'app',
components: {
'app-header': header
},
methods: {
logout: function() {
firebase.auth().signOut().then(() => {
this.$router.replace('login')
})
}
}
}
</script>
Login.vue
import firebase from 'firebase'
import db from '../firebaseInit'
const postRef = db.ref('posts')
export default {
name: 'login',
data: function() {
return {
email: '',
password: ''
}
},
methods: {
signIn: function() {
firebase.auth().signInWithEmailAndPassword(this.email, this.password).then(
(user) => {
this.$router.replace('/')
},
(err) => {
alert('Oops ' + err.message)
}
);
}
}
}
</script>
addPost.vue
<template>
<div id="add-blog">
<h2>Add a New Post</h2>
<form v-if="!submitted">
<label>Title:</label>
<input type="text" v-model="newPost.title" required />
<p>{{ getDate }}</p>
<label for="">Content:</label>
<textarea v-model.trim="newPost.content"></textarea>
<div id="checkboxes">
<p>Categories:</p>
<label>Vue.js</label>
<input type="checkbox" value="vue" v-model="newPost.categories" />
<label>CSS Magic</label>
<input type="checkbox" value="css" v-model="newPost.categories" />
</div>
<label>Author:</label>
<select v-model="newPost.author">
<option v-for="author in authors">{{ author }}</option>
</select>
<button #click.prevent="addPost">Add Post</button>
</form>
<div v-if="submitted">
<p>Congraturation!</p>
</div>
<div id="preview">
<h3>Preview Post</h3>
<h4>Title {{ newPost.title }}</h4>
<h4>Content </h4>
<p style="white-space: pre">{{ newPost.content }}</p>
<ul>
<li v-for="category in newPost.categories">{{ category }}</li>
</ul>
<p>{{ newPost.author }}</p>
</div>
</div>
</template>
<script>
import db from '../firebaseInit'
const postRef = db.ref('posts')
export default {
data() {
return {
newPost: {
date: '',
title: '',
author: '',
content: '',
categories: []
},
authors: ['Naeun', 'Raphael'],
submitted: false,
items: []
}
},
methods: {
addPost: function() {
postRef.push(this.newPost)
this.newPost.date = '',
this.newPost.title = '',
this.newPost.author = '',
this.newPost.content = '',
this.newPost.categories = ''
},
removePost: function() {
postRef.child(post['.key']).remove()
}
},
computed: {
getDate: function() {
const toTwoDigits = num => num < 10 ? '0' + num : num;
let today = new Date();
let year = today.getFullYear();
let month = toTwoDigits(today.getMonth() + 1);
let day = toTwoDigits(today.getDate());
return this.newPost.date = `${year}-${month}-${day}`;
}
}
}
</script>
Make sure that the next function is called exactly once in any given pass through the navigation guard. It can appear more than once, but only if the logical paths have no overlap, otherwise the hook will never be resolved or produce errors.
Your else if condition else if (!requiresAuth && currentUser) next('/') violates this rule.
Change your route guarding logic
// check if route requiresAuth
router.beforeEach((to, from, next) => {
if (to.matched.some(rec => rec.meta.requiresAuth)) {
const user = firebase.auth().currentUser;
// check auth state of user
user ? next() : next('/login') // user not signed in, route to login
} else {
next(); // route does not require auth
}
});
https://router.vuejs.org/guide/advanced/navigation-guards.html#global-before-guards
Hope this helps.

Resources