I have a small problem with the display of the Authentication with VueJs page.
Once on the authentication User page I also have the menu which remains displayed, and once authenticated it redirects me to the Home page however when I disconnect I have the same concerns, it redirects me to the authenticationUser page but with the menu that remains displayed.
and if I do a refresh on the authenticationUser page the page remains blank without error.
I don't know if you have any idea for the cause of the problem.
Thanks in advance.
Page App.vu
<template>
<v-app id='inspire'>
<div v-if="user && user.sub">
<Menu />
</div>
</v-app>
</template>
<script>
import AuthentificationUser from "./views/AuthentificationUser";
import AuthenticatedUserUtils from "./utils/AuthenticatedUserUtils";
import Header from './components/common/Header';
import Menu from './components/common/Menu';
export default {
name: "app",
data: () => ({
user: AuthenticatedUserUtils.user
}),
components: {
AuthentificationUser,
Menu
},
};
</script>
enter code here
Router.ts
import User from '../models/User'
import Vue from 'vue'
import VueRouter, { RouteConfig } from 'vue-router'
import AuthenticatedUserUtils from '../utils/AuthenticatedUserUtils'
Vue.use(VueRouter)
const routes: Array<RouteConfig> = [
{
path: '/',
meta: {
requireAuth: true,
}
},
{
path: '/inventory',
name: 'Inventory',
meta: {
requireAuth: true,
}
},
{
path: '/inventory/authentificationUser',
name: 'AuthentificationUser',
component: () => import('../views/AuthentificationUser.vue')
},
{
path: '/inventory/home',
name: 'Home',
component: () => import('../views/Home.vue'),
meta: {
requireAuth: true,
}
},
{
path: '/inventory/parametrage',
name: 'Parametrage',
component: () => import('../views/Parametrage.vue'),
meta: {
requireAuth: true,
}
},
{
path: '/inventory/rfid',
name: 'RFID',
component: () => import('../views/RFID.vue'),
meta: {
requireAuth: true,
}
}
]
const router = new VueRouter({
mode: 'history',
base: process.env.BASE_URL,
routes
})
router.beforeEach((to, from, next) => {
if (!!to && !!to.meta && to.meta.requireAuth) {
// TODO : voir si le cookie existe et est valide
if (document && document.cookie) {
const potentialCookie = document.cookie
.split('; ')
.find(row => row.startsWith('access_token='));
let token = '';
if (potentialCookie) {
token = potentialCookie.split('=')[1];
}
const parsedJwt = parseJwt(token);
if (new Date() <= new Date(parsedJwt.exp * 1000)) {
const usr:User = new User();
usr.created = parsedJwt.created;
usr.sub =JSON.parse(JSON.stringify(parsedJwt.sub));
usr.exp = parsedJwt.exp;
AuthenticatedUserUtils.user = usr;
next();
} else {
AuthenticatedUserUtils.user = undefined;
// token non valide sur une page qui a besoin de l'authent
router.push('/inventory/authentificationUser').catch(()=>{});;
}
} else {
router.push('/inventory/authentificationUser').catch(()=>{});;
}
} else {
// appInsights.trackPageView({ name: to.name });
next();
}
});
function parseJwt (token: string) {
var base64Url = token.split('.')[1];
var base64 = base64Url.replace(/-/g, '+').replace(/_/g, '/');
var jsonPayload = decodeURIComponent(atob(base64).split('').map(function(c) {
return '%' + ('00' + c.charCodeAt(0).toString(16)).slice(-2);
}).join(''));
return JSON.parse(jsonPayload);
};
export default router
enter code here
Menu.ts
<template>
<v-app>
<v-navigation-drawer color="#80e27e" app v-model='drawer'>
<div style="background-color: #F5F5F5; width:260px;height:63px;">
<v-list-item-title class="text-h6" style="text-align:center; padding-top: 5%; color: #087f23;">{{ $t("label.inventaire") }}</v-list-item-title>
</div>
<v-list dense nav>
<template v-for='item in items'>
<v-list-item :key='item.text' #click="goToRoute(item.to)">
<v-list-item-icon>
<v-icon v-text="item.icon" style="color: #087f23;" />
</v-list-item-icon>
<v-list-item-content>
<v-list-item-title v-text="item.title" style="color: #087f23;"/>
</v-list-item-content>
</v-list-item>
</template>
</v-list>
<template>
<div style="color: #087f23; margin-top: 150%;">
<b><span block style="color: #087f23; margin-left: 23%; ">{{ $t("label.bienvenue") }} Frédéric</span></b>
<div style="width:150px;height:35px;border:0px solid #000;border-radius:5px;-webkit-border-radius:5px;margin-left: 20%;background-color: #F5F5F5;">
<img v-if="checkValueCodeLangueMenu() === true" style="width:35px; height:35px; margin-left:39%; border-radius:5px;-webkit-border-radius:5px;" src="#/assets/fra.png"/>
<img v-if="checkValueCodeLangueMenu() === false" style="width:27px; height:27px; margin-left:39%; margin-top:2%; border-radius:5px;-webkit-border-radius:5px;" src="#/assets/eng.png"/>
</div>
<v-btn style="color: #087f23; margin-top: 10%;width:200px;height:35px; margin-left: 10%;" #click="logout()">
<v-icon>mdi-logout</v-icon>
<label>{{ $t("label.deconnexion") }}</label>
</v-btn>
</div>
</template>
</v-navigation-drawer>
<v-app-bar app color="#4caf50">
<v-app-bar-nav-icon #click="drawer = !drawer" style="color: #087f23;"></v-app-bar-nav-icon>
<v-spacer></v-spacer>`
<v-menu offset-y>`enter code here`
<template v-slot:activator="{ on }">
<div class="text-center">
<v-btn icon v-on="on">
<v-icon> mdi-earth </v-icon>
</v-btn>
</div>
</template>
<v-list>
<v-list-item
v-for="langue in languesDispo"
:key="langue.codeLangue"
#click="changeLocale(langue)"
>
<v-list-item-title>
<img v-if="checkValueCodeLangue(langue.codeLangue) === true" style="width:26px; height:26px;border-radius:5px;-webkit-border-radius:8px;vertical-align:middle" src="#/assets/fra.png"/>
<img v-if="checkValueCodeLangue(langue.codeLangue) === false" style="width:26px; height:26px;border-radius:5px;-webkit-border-radius:8px;vertical-align:middle" src="#/assets/eng.png"/>
</v-list-item-title>
</v-list-item>
</v-list>
</v-menu>
<v-icon v-on:click="logout()">mdi-logout</v-icon>
</v-app-bar>
<v-main >
<v-container fluid>
<router-view/>
</v-container>
</v-main>
</v-app>
</template>
<script lang="ts">
import Vue from 'vue'
import i18n from '#/plugins/i18n';
import Langue from '#/models/Langue';
import PaysUtils from '#/utils/PaysUtils';
export default Vue.extend({
name: 'Menu',
data: () => ({
currentPays: 'fr',
languesDispo: PaysUtils.lstPays,
drawer: null,
imgLangue: null,
items: [
{ title: 'Accueil', icon: 'mdi-home', to: '/' },
{ title: 'Paramétrage', icon: 'mdi-cog', to: '/inventory/parametrage' },
{ title: 'RFID', icon: 'mdi-help-box', to: '/inventory/rfid' },
],
}),
methods: {
logout (){
document.cookie = "";
this.$router.push('/inventory/authentificationUser').catch(()=>{});
},
goToRoute(route: string): void {
this.$router.push(route);
},
changeLocale(langue: Langue): void {
if (langue.codeLangue && langue.codePays) {
this.$vuetify.lang.current = langue.codeLangue;
i18n.locale = langue.codeLangue;
this.currentPays = langue.codePays;
}
},
checkValueCodeLangue : function(langue: String) {
if(langue === 'fra') {
return true
}
return false
},
checkValueCodeLangueMenu : function() {
if(this.currentPays === 'fr'){
return true
}
return false
}
},
})
</script>
Related
I have 3 components like: Parent, First-child and Second-child. And I am iterating First-child in Parent component in array(it is cards), and I want to call Second-child in Parent component with First-child's props(props of one card).
My Parent component looks like this(how I am calling First-child):
``
<CardComponent
v-for="card of cards"
:key="card.urlsId"
:cardImages="card.images"
:cardTitle="card.title"
:cardDescription="card.description"
:mediaRef="card.urlsId"
:dbRef="card.dbId"
:deleteBtn="true"
:imagesWithSlider="true"
/>
And my First child is:
<template>
<div class="cards">
<v-card class="card-container">
<div class="delete-btn">
<v-btn
v-if="deleteBtn"
class="mx-2"
fab
dark
small
#click="$emit('onOpenDeleteModal')"
>
<v-icon dark> mdi-delete </v-icon>
</v-btn>
</div>
<ImageSlider
v-if="imagesWithSlider"
:imagesArray="cardImages"
:arrowBtns="false"
/>
<div class="text-container">
<h3 class="card-title">{{ cardTitle }}</h3>
<p class="card-description">{{ cardDescription }}</p>
</div>
</v-card>
</div>
</template>
<script>
export default {
props: {
cardImages: {
type: Array,
default: null,
},
cardTitle: {
type: String,
default: 'Title',
},
cardDescription: {
type: String,
default: 'Description',
},
deleteBtn: {
type: Boolean,
},
imagesWithSlider: {
type: Boolean,
},
mediaRef: {
type: String,
default: '',
},
dbRef: {
type: String,
default: '',
},
deleteModalOpen: {
type: Boolean,
},
},
emits: ['onOpenDeleteModal', 'onCloseDeleteModal'],
}
</script>
And my Second-child is:
<template>
<v-card class="modal" :loading="newCard.loading ? true : false">
<v-card class="modal-header">
<h3 v-if="addCardModal" class="header-title">New card</h3>
<h3 v-if="deleteModal" class="header-title">Delete</h3>
<v-icon aria-hidden="false" width="100%" #click="$emit('closeModal')"
>mdi-close</v-icon
>
</v-card>
<!-- Delete Modal -->
<div v-if="deleteModal" class="modal-delete">
<h3>Are you really want to delete this card ?</h3>
<div class="modal-delete-btns">
<v-btn #click="$emit('closeModal')">Cancel</v-btn>
<v-btn color="error" #click="$emit('onDeleteCard')">Delete</v-btn>
</div>
</div>
<!-- Add New Card Modal -->
<form
v-if="addCardModal"
class="modal-container"
#submit.prevent="postNewCardToDb"
>
<v-file-input
v-model="newCard.cardImages"
:clearable="false"
multiple
show-size
label="Upload card images"
#change="previewImage"
>
</v-file-input>
<v-file-input
v-model="newCard.cardVideo"
:clearable="false"
show-size
label="Upload video"
>
</v-file-input>
<div v-if="newCard.cardImageUrls.length !== 0" class="preview-image">
<ImageSlider :imagesArray="newCard.cardImageUrls" :arrowBtns="true" />
</div>
<v-text-field
v-model="newCard.cardTitle"
label="Enter card title"
></v-text-field>
<v-text-field
v-model="newCard.cardSnippet"
label="Enter card description"
></v-text-field>
<v-btn type="submit" :loading="newCard.loading ? true : false" block
>POST</v-btn
>
</form>
</v-card>
</template>
<script>
import { v4 as uuidV4, v1 as uuidV1 } from 'uuid'
export default {
/* eslint-disable no-console */
props: {
addCardModal: {
type: Boolean,
},
deleteModal: {
type: Boolean,
},
},
emits: ['closeModal', 'onDeleteCard'],
data() {
return {
newCard: {
loading: false,
cardImages: [],
cardVideo: null,
cardImageUrls: [],
cardTitle: '',
cardSnippet: '',
},
}
},
methods: {
previewImage($event) {
for (const image of event.target.files) {
this.newCard.cardImageUrls.push(URL.createObjectURL(image))
}
},
async getMediaUrlsFromStorage(newCardData) {
const cardMediaRef = uuidV1()
const cardImagesRef = await this.$fire.storage
.ref('/albums_cards/')
.child(cardMediaRef)
const videoRef = await cardImagesRef.child(uuidV4())
if (this.newCard.cardVideo) {
await videoRef.put(this.newCard.cardVideo)
const videoUrl = await videoRef.getDownloadURL()
newCardData.video = videoUrl
}
newCardData.urlsId = cardMediaRef
const promiseArr = this.newCard.cardImages.map(async (image) => {
const imageRef = cardImagesRef.child(uuidV4())
await imageRef.put(image)
const imageUrl = await imageRef.getDownloadURL()
newCardData.images.push(imageUrl)
})
await Promise.all(promiseArr)
},
async postNewCardToDb() {
this.newCard.loading = true
const newCardData = {
urlsId: '',
title: this.newCard.cardTitle,
description: this.newCard.cardSnippet,
video: '',
images: [],
}
await this.getMediaUrlsFromStorage(newCardData)
await this.$fire.database.ref('albums/cards').push(newCardData)
console.log(newCardData)
this.newCard.loading = false
this.newCard.cardTitle = null
this.newCard.cardSnippet = null
this.newCard.cardImages = []
this.newCard.cardImageUrls = []
this.newCard.cardVideo = null
},
},
}
</script>
First-child is a card component and I need to pass props of each card to Second-child without calling it. I cant call Second-child in First-child because of iteration.
I hope I expleined it well
I have an error trying to get data from my vuex store.
Property or method "cart" is not defined on the instance but referenced during render. Make sure that this property is reactive, either in the data option, or for class-based components, by initializing the property.
Property or method "cartItems" is not defined on the instance but referenced during render. Make sure that this property is reactive, either in the data option, or for class-based components, by initializing the property
pages/cart.vue
<template>
<div>
<v-container>
<section>
<h2 class="my-4">Your Cart</h2>
<v-divider class="my-4"></v-divider>
<h3>Total Amount: ${{ cart }}</h3>
<CartItem
v-for="item in cartItems"
:key="item.productId"
:prod-id="item.productId"
:name="item.name"
:image="item.image"
:price="item.price"
:qty="item.qty"
></CartItem>
</section>
</v-container>
</div>
</template>
<script>
import CartItem from '../components/CartItem'
import { mapGetters } from 'vuex'
export default {
components: {
CartItem,
computed: {
...mapGetters('cart',['totalSum'])
},
cartItems(){
return this.$store.getters['cart/products'];
}
}
}
</script>
<style scoped>
h2{
text-align: center;
}
h3{
text-align: center;
}
</style>
./components/CartItem.vue
<template>
<v-container class="my-5">
<v-row>
<v-col
sm="6"
md="4"
>
<v-card outlined>
<v-img :src="image" height="200px" />
<v-card-title> {{ name}} </v-card-title>
<v-card-subtitle> ${{ price }}</v-card-subtitle>
<v-card-subtitle> Quantity <strong>{{ qty }}</strong> </v-card-subtitle>
<v-card-actions>
<div>Total: ${{ itemTotal }}</div>
<v-btn #click="remove()" color="success" outlined >
<v-icon small left> add </v-icon>
Remove
</v-btn>
</v-card-actions>
</v-card>
</v-col>
</v-row>
</v-container>
</template>
<script>
export default {
props: ['prodId', 'name', 'image', 'price', 'qty'],
computed: {
itemTotal() {
return( this.price * this.qty).toFixed(2);
}
},
methods: {
remove(){
this.$store.dispatch('cart/removeFromCart', {productId: this.prodId})
}
}
}
</script>
store/modules/cart.js
export default {
namespaced: true,
state(){
return{
items: [],
total: 0,
qty: 0
}
},
mutations: {
addProductToCart(state, payload) {
const productData = payload;
const productInCartIndex = state.items.findIndex(
(ci) => ci.productId === productData.id
);
if (productInCartIndex >= 0) {
state.items[productInCartIndex].qty++;
} else {
const newItem = {
productId: productData.id,
title: productData.title,
image: productData.image,
price: productData.price,
qty: 1,
};
state.items.push(newItem);
}
state.qty++;
state.total += productData.price;
},
removeProductFromCart(state, payload) {
const prodId = payload.productId;
const productInCartIndex = state.items.findIndex(
(cartItem) => cartItem.productId === prodId
);
const prodData = state.items[productInCartIndex];
state.items.splice(productInCartIndex, 1);
state.qty -= prodData.qty;
state.total -= prodData.price * prodData.qty;
},
},
actions: {
addToCart(context, payload) {
const prodId = payload.id;
const products = context.rootGetters['prods/products'];
const product = products.find(prod => prod.id === prodId);
context.commit('addProductToCart', product);
},
removeFromCart(context, payload) {
context.commit('removeProductFromCart', payload);
}
},
getters: {
products(state) {
return state.items;
},
totalSum(state) {
return state.total;
},
quantity(state) {
return state.qty;
}
}
}
The property cartItems should be added to the computed option like :
export default {
components: {
CartItem,
},
computed: {
...mapGetters('cart',['totalSum']),
cartItems(){
return this.$store.getters['cart/products'];
}
}
}
i used snackbar to show success messages in vuejs. i want to make a global custom snackbar component.
<template>
<div name="snackbars">
<v-snackbar
v-model="snackbar"
:color="color"
:timeout="timeout"
:top="'top'"
>
{{ text }}
<template v-slot:action="{ attrs }">
<v-btn dark text v-bind="attrs" #click="snackbar = false">
Close
</v-btn>
</template>
</v-snackbar>
</div>
</template>
<script>
export default {
props: {
snackbar: {
type: Boolean,
required: true,
},
color: {
type: String,
required: false,
default: "success",
},
timeout: {
type: Number,
required: false,
default: 3000,
},
text: {
type: String,
required: true,
},
},
};
</script>
then i import this as a component in my every form like this.
<SnackBar :snackbar="snackbar" :color="color" :text="text" />
but my issue is i can't use snackbar as a prop in my child component. it shows me this error.
Avoid mutating a prop directly since the value will be overwritten whenever the parent component re-renders. Instead, use a data or computed property based on the prop's value. Prop being mutated: "snackbar"
how can i fix this issue. can anyone help me?
I realize this is old, but thanks to google, I am going to add my solution.
I use this, because I don't see the point of using vuex for a snackbar. It's more work then needed.
Create a vue component named vtoast
<template>
<v-snackbar
:color="color"
:timeout="timer"
v-model="showSnackbar"
bottom
right
>
<v-icon left>{{icon}}</v-icon>{{message}}
</v-snackbar>
</template>
<script>
export default {
name: "vtoast",
data() {
return{
showSnackbar: false,
message: '',
color: 'success',
icon: 'mdi-check',
timer: 3000
}
},
methods:{
show(data) {
this.message = data.message || 'missing "message".'
this.color = data.color || 'success'
this.timer = data.timer || 3000
this.icon = data.icon || 'mdi-check'
this.showSnackbar = true
}
}
}
</script>
Somewhere in the root of your main app, add the following. (I usually put mine in App.vue)
<template>
...
<!-- toast -->
<vtoast ref="vtoast"/>
...
</template>
<script>
import vtoast from '#/your/vtoast/directory/vtoast'
export default{
name: 'App', //or whatever your root is
components:{
vtoast
},
mounted() {
this.$root.vtoast = this.$refs.vtoast
},
}
</script>
And access it like so...
this.$root.vtoast.show()
this.$root.vtoast.show({message: 'Ahoy there!'})
i found a way to fix my solution using vuex.
<template>
<div name="snackbars">
<v-snackbar v-model="show" :color="color" :timeout="timeout" :top="'top'">
{{ text }}
<template v-slot:action="{ attrs }">
<v-btn dark text v-bind="attrs" #click="show = false">
Close
</v-btn>
</template>
</v-snackbar>
</div>
</template>
<script>
export default {
created() {
this.$store.subscribe((mutation, state) => {
if (mutation.type === "snackbar/SHOW_MESSAGE") {
this.text = state.snackbar.text;
this.color = state.snackbar.color;
this.timeout = state.snackbar.timeout;
this.show = true;
}
});
},
data() {
return {
show: false,
color: "",
text: "",
timeout: 0,
};
},
};
</script>
in my vuex module i wrote like this
export default {
namespaced: true,
state: {
text: "",
color: "",
timeout: "",
},
mutations: {
SHOW_MESSAGE(state, payload) {
state.text = payload.text;
state.color = payload.color;
state.timeout = payload.timeout;
},
},
actions: {
showSnack({ commit }, payload) {
commit("SHOW_MESSAGE", payload);
},
},
};
then i import snackbar child component into my parent component and send data like this.
...mapActions("snackbar", ["showSnack"]),
saveDetails() {
this.showSnack({
text: "Successfully Saved!",
color: "success",
timeout: 3500,
});
}
Another solution is to use a computed value with getter and setter.
Using options api
<template>
<v-snackbar v-model="show" :color="color">
{{ message }}
<template v-slot:action="{ attrs }">
<v-btn text v-bind="attrs" #click="show = false">Close</v-btn>
</template>
</v-snackbar>
</template>
<script>
import { mapGetters } from 'vuex';
export default {
computed: {
...mapGetters({
message: 'snackbar/message',
color: 'snackbar/color'
}),
show: {
get() {
return this.$store.state.snackbar.show
},
set(v) {
this.$store.commit('snackbar/SET_SHOW', v)
}
}
}
}
</script>
Using composition api plugin
<template>
<v-snackbar v-model="show" :color="color">
{{ message }}
<template v-slot:action="{ attrs }">
<v-btn text v-bind="attrs" #click="show = false">Close</v-btn>
</template>
</v-snackbar>
</template>
<script>
import { defineComponent, computed } from '#vue/composition-api';
export default defineComponent({
setup(_props, { root }) {
const show = computed({
get: () => root.$store.state.snackbar.show,
set: (v) => root.$store.commit('snackbar/SET_SHOW', v),
});
const message = computed(() => root.$store.state.snackbar.message);
const color = computed(() => root.$store.state.snackbar.color);
return {
show,
message,
color,
};
},
});
</script>
A better implementation using composables here https://gist.github.com/wobsoriano/2f3f0480f24298e150be0c13f93bac20
You are having a prop and the same in data.
remove snackbar from data() as it is available from prop.
<script>
export default {
props: {
snackbar: {
type: Boolean,
required: true,
},
color: {
type: String,
required: false,
default: "success",
},
timeout: {
type: Number,
required: false,
default: 3000,
},
text: {
type: String,
required: true,
},
}
};
</script>
This is what I did with Options API with mere props and events;
Here is the Snackbar.vue component
<template>
<div class="text-center">
<v-snackbar
transition="true"
bottom
right
v-model="show"
:color="snackbar.color"
:timeout="snackbar.timeout"
class="snackbar-shadow"
>
<div class="d-flex align-start alert-notify">
<v-icon size="24" class="text-white mr-5">{{ snackbar.icon }}</v-icon>
<p class="mb-0">
<span class="font-size-root font-weight-600">{{
snackbar.title
}}</span>
<br />
{{ snackbar.message }}
</p>
</div>
<template v-slot:action="{ attrs }">
<v-btn
icon
elevation="0"
max-width="136"
:ripple="false"
height="43"
class="font-weight-600 text-capitalize py-3 px-6 rounded-sm"
color="rgba(255,255,255, .85)"
text
v-bind="attrs"
#click="show = false"
>
<v-icon size="13">fas fa-times</v-icon>
</v-btn>
</template>
</v-snackbar>
</div>
</template>
<script>
export default {
name: "snackbar",
props: {
snackbar: Object,
},
computed: {
show: {
get() {
return this.snackbar.visible;
},
set(value) {
this.$emit("closeSnackbar", value);
},
},
},
};
</script>
Here is the App.vue component
<template>
<!-- Snackbar -->
<snackbar :snackbar="snackbar" #closeSnackbar="SnackbarClose"></snackbar>
</template>
<script>
export default {
name: "app",
data() {
return {
snackbar: {
visible: false,
timeout: 2000,
color: "#11cdef",
title: "Hello",
message: null,
icon: "fas fa-bell",
},
};
},
created: { this.SnackbarShow(); }
methods: {
SnackbarShow() {
this.snackbar.visible = true;
this.snackbar.message = "Hola!👋 I'm a snackbar";
},
SnackbarClose() {
this.snackbar.visible = false;
},
},
};
</script>
Im a noob in vuejs and i want to pass some data : profile that you can find inside of created() into
<span v-if="isLoggedIn">{{this.profile.username}}</span>
I know i'm missing some basics behind how vue works but im still learnig:)
<template>
<v-card class="mx-auto" color="dark" dark>
<div>
<v-app-bar clipped-left dark app>
<v-app-bar-nav-icon class="grey--text" #click="drawer= !drawer"></v-app-bar-nav-icon>
<v-toolbar-title class="grey--text">
<span class="font-weight-light">anime</span>
<span>Art</span>
</v-toolbar-title>
<v-spacer></v-spacer>
<span v-if="isLoggedIn">hi{{profile.username}}</span>
<v-btn icon>
<v-icon>mdi-heart</v-icon>
</v-btn>
<v-btn icon to="/login">
<v-icon>mdi-account-outline</v-icon>
</v-btn>
<v-btn icon v-if="isLoggedIn">
<v-icon v-on:click="logout">mdi-logout-variant</v-icon>
</v-btn>
</v-app-bar>
</div>
<v-navigation-drawer app expand-on-hover clipped v-model="drawer">
<v-divider></v-divider>
<v-list nav>
<v-list-item v-for="item in items" :key="item.title" :to="item.path" link>
<v-list-item-icon>
<v-icon>{{ item.icon }}</v-icon>
</v-list-item-icon>
<v-list-item-content>
<v-list-item-title>{{ item.title }}</v-list-item-title>
</v-list-item-content>
</v-list-item>
</v-list>
</v-navigation-drawer>
</v-card>
</template>
<script>
import firebase from "firebase";
// import db from "#/Firebase/firebaseInit";
export default {
data() {
return {
profile: {},
name: "navbar",
isLoggedIn: false,
currentUser: false,
drawer: false,
items: [
{ title: "Anime Home", icon: "mdi-view-dashboard", path: "/" },
{
title: "Trends",
icon: "mdi-chart-line-stacked",
path: "/trends"
},
{ title: "Save", icon: "mdi-bookmark", path: "/save" },
{
title: "Profile",
icon: "mdi-badge-account-horizontal",
path: "/profile"
},
{ title: "About", icon: "mdi-label", path: "/about" }
],
right: null
};
},
created() {
this.profile = {username:'hello'}
var user = firebase.auth().currentUser;
// var name, email,uid;
//, photoUrl, emailVerified
if (user != null) {
this.isLoggedIn = true;
this.profile = {
username: user.displayName,
useremail: user.email,
userid: user.uid,
photoUrl: user.photoURL,
emailVerified: user.emailVerified
};
console.log(profile.username);
// The user's ID, unique to the Firebase project. Do NOT use
// this value to authenticate with your backend server, if
// you have one. Use User.getToken() instead.
}
// console.log(user)
},
methods: {
logout: function() {
firebase
.auth()
.signOut()
.then(function() {
// Sign-out successful.
if (!firebase.auth().currentUser) {
alert("Signed out successfuly ");
}
})
.catch(function(error) {
// An error happened.
alert(error.message);
});
this.isLoggedIn = false;
this.$router.go({ path: this.$router.path });
}
}
};
</script>
in your html :
<span v-if="isLoggedIn">{{profile.username}}</span>
in your script
<script>
import firebase from "firebase";
export default {
data() {
return {
profile: {},
//all your stuff
},
created() {
var user = firebase.auth().currentUser;
if (user != null) {
this.isLoggedIn = true;
this.profile = {
username:user.displayName,
useremail :user.email,
userid:user.uid,
photoUrl : user.photoURL,
emailVerified: user.emailVerified
}
}
// console.log(user)
},
methods: {//all your stuff }
};
</script>
I am trying to re-use the same component, but load the components with different data. I thought simply providing unique id's would do the trick, but no luck. I switched from a Vuex store for this data, to using a dataShare This is what I'm doing:
The components:
<logoHeader :panel=0 title="Add your logo / header" id="top" topPadding="pt-10" />
<logoHeader :panel=1 title="Add your main image" id="main" topPadding="pt-0"/>
So its the exact same component, with some different props and different ids
This is the logoHeader component:
<template>
<v-row
:class="topPadding"
align="center"
justify="center"
>
<v-col
align="center"
justify="center"
cols="12"
>
<v-hover v-slot:default="{ hover }">
<v-card
:elevation="hover ? 12 : 0"
class="mx-auto"
max-width="600"
>
<v-img
v-if="showImage"
:src="imageUrl"
max-width="600px"
class="pointer"
#click="panel = 0"
>
</v-img>
<v-icon
v-if="!showImage"
class="my_dark_purple_text"
size="100"
#click="sendToPanel"
>add_box</v-icon>
<p class="my_dark_purple_text">{{ title }}</p>
<p>URL {{ imageUrl }}</p>
<p>Show image? {{ showImage }}</p>
</v-card>
</v-hover>
</v-col>
</v-row>
</template>
<script>
import {mapGetters} from 'vuex';
import {mapActions} from 'vuex';
import {dataShare} from '../../../packs/fresh-credit.js';
export default {
props: ['panel', 'title', 'topPadding'],
data() {
return {
imageUrl: "",
showImage: false,
}
},
created() {
dataShare.$on('imageUrl', (data) => {
this.imageUrl = data;
});
dataShare.$on('showImage', (data) => {
this.showImage = data;
});
},
computed: {
...mapGetters('emailPanel', [
'returnPanel'
]),
},
methods: {
...mapActions('emailPanel', [
'updatePanel'
]),
sendToPanel() {
this.updatePanel(this.panel);
},
},
}
</script>
And then finally this is where the data enters the system:
<template>
<v-expansion-panel-content>
<h1 class="subtitle-1 font-weight-bold">Only images files accepted</h1>
<v-file-input
v-model="image"
accept="image/*"
label="Image Upload"
prepend-icon="add_a_photo"
color='#68007d'
></v-file-input>
<v-btn
:disabled="disableUpload"
color="#68007d"
class="white--text"
#click="sendImage"
>Submit</v-btn>
</v-expansion-panel-content>
</template>
<script>
import axios from 'axios';
import {dataShare} from '../../../../packs/fresh-credit.js';
export default {
data() {
return {
image: null,
disableUpload: true,
}
},
watch: {
image: function() {
if(this.image.size > 0){
this.disableUpload = false;
}
else{
this.disableUpload = true;
}
}
},
computed: {
},
methods: {
sendImage() {
let formData = new FormData();
formData.append('file', this.image);
axios.post('/admin/features/images', formData,
{
headers: {
'Content-Type': 'multipart/form-data'
}
}
).then(response => {
dataShare.$emit('imageUrl', response.data);
dataShare.$emit('showImage', true);
});
}
},
}
</script>
Where did I go astray?
Add the key property to the components and set it to different values (for example 1 and 2). If the key has different values Vue will differentiate them when rendering. Here is a basic explanation.