After Login my menu has to change "connexion" to "deconnexion" but it not happening.
I have :
LoginPage.vue :
<fg-input addon-left-icon="now-ui-icons ui-1_email-85"
v-model="email"
placeholder="Email">
</fg-input>
<fg-input addon-left-icon="now-ui-icons text_caps-small"
v-model="password"
placeholder="Mot de passe">
</fg-input>
<template slot="raw-content">
<div class="card-footer text-center">
<a href="#pablo" class="btn btn-primary btn-round btn-lg btn-block"
#click.prevent="login">Se connecter</a>
</div>
....
<script>
....
methods: {
...mapActions(['loginUser']),
login(){
if (this.email.length > 0 && this.password.length > 0) {
this.loginUser({
email: this.email,
password: this.password,
})
} else {
this.password = ""
return alert("Passwords do not match")
}
....
Store.js :
state:{
user: {},
token : "",
loggedIn: false
},
getters:{
user : state =>{ return state.user },
token : state =>{ return state.token },
},
mutations:{
SET_USER:(state,newValue)=>{
return state.user = newValue
},
SET_TOKEN:(state,newValue)=>{
return state.token = newValue
},
SET_LOGGEDIN:(state, newValue)=>{
return state.loggedIn = newValue
},
},
actions:{
loginUser({commit,state}, payload){
axios.post("http://127.0.0.1:8000/api/auth/login", payload)
.then(response => {
commit('SET_TOKEN', JSON.stringify(response.data.accessToken))
commit('SET_LOGGEDIN', true)
router.push({name:'accueil'})
})
.catch(error => {
console.log(error);
});
},
StarterNavbar.vue :
<template v-if="loggedIn" >
<li class="nav-item nav-link" style="cursor: pointer;" #click.prevent="logoutUser">
Deconnexion
</li>
</template>
<template v-else>
<router-link class="nav-item nav-link" to="/register">
Inscription
</router-link>
<router-link class="nav-item nav-link" to="/login">
Connexion
</router-link>
</template>
....
computed:{
...mapState(['loggedIn', 'token']),
},
After Login action the router push to home page (Accueil.vue).
In this component I trace 'loggedIn' and 'token' properties of Store.
mounted() {
console.log('token',this.token) // exist
console.log('loggedIn', this.loggedIn) // true
But I don't see the changes in my StarterNavbar : Connexion is displayed instead Deconnexion.
Why my menu is changing just after reload of page?
In Vue-devtools after Login action:
switch to Components :
vuex bindings
loggedIn: true
token: ""eyJ0eXAiOiJKV1QiLCJ...""
switch to Vuex:
mutation
payload:true
type:"SET_LOGGEDIN"
but STATE is grey, params have old value... and on bottom the following is written:
Recording state on demande.... displaying last received state and button "Load state". If I click on it State become black and params have new values.. the page not updated.
What does it mean and what happens?
Related
For auth I do use nuxt-auth, when the login is successful, I want to redirect to the main page using this.$router.push('/'), then I get a response like blank page with the following message
2021
,
// for login
<template>
<div class="limiter">
<div
class="container-login100"
:style="{
backgroundImage: 'url(' + require(`#/assets/login/images/bg-01.jpg`) + ')',
}"
>
<div class="wrap-login100 p-l-110 p-r-110 p-t-62 p-b-33">
<form class="login100-form validate-form flex-sb flex-w">
<span class="login100-form-title p-b-53"> Login Admin </span>
<a href="facebook.com" class="btn-face m-b-20">
<i class="fa fa-facebook-official"></i>
Facebook
</a>
<a href="google.com" class="btn-google m-b-20">
<img :src="require(`#/assets/login/images/icons/icon-google.png`)" alt="GOOGLE" />
Google
</a>
<div class="p-t-31 p-b-9">
<span class="txt1"> Email </span>
</div>
<div class="wrap-input100 validate-input" data-validate="Email is required">
<input v-model="auth.email" class="input100" type="email" name="email" />
<span class="focus-input100"></span>
</div>
<div class="p-t-13 p-b-9">
<span class="txt1"> Password </span>
Forgot?
</div>
<div class="wrap-input100 validate-input" data-validate="Password is required">
<input v-model="auth.password" class="input100" type="password" name="pass" />
<span class="focus-input100"></span>
</div>
<div class="container-login100-form-btn m-t-17">
Login
</div>
<div class="w-full text-center p-t-55">
<span class="txt2"> Not a member? </span>
Register now
</div>
</form>
</div>
</div>
</div>
</template>
<script>
export default {
auth: false,
data() {
return {
auth: {
email: null,
password: null,
},
}
},
mounted() {
if (this.$auth.loggedIn) {
this.$router.push('/')
}
},
methods: {
async submit() {
try {
const response = await this.$auth.loginWith('local', { data: this.auth })
this.$router.push('/')
} catch (err) {
console.log(err)
}
},
},
}
</script>
store vuex index.js
export const getters = {
isAuthenticated(state) {
return state.auth.loggedIn
},
loggedInUser(state) {
return state.auth.user
}}
}
layout default.vue
<template>
<div class="wrapper">
<Sidebar v-if="isAuthenticated" />
<div :class="isAuthenticated ? 'main-panel' : ''">
<Navbar v-if="isAuthenticated" />
<Nuxt />
<Footer v-if="isAuthenticated" />
</div>
</div>
</template>
<script>
import Sidebar from '#/components/layout/Sidebar.vue'
import Navbar from '#/components/layout/Navbar.vue'
import Footer from '#/components/layout/Footer.vue'
import { mapGetters } from 'vuex'
export default {
components: { Sidebar, Navbar, Footer },
computed: {
...mapGetters(['isAuthenticated', 'loggedInUser']),
},
}
</script>
// auth nuxt config
auth : {
strategies: {
local: {
token: {
property: 'token',
required: true,
type: 'Bearer'
},
user: {
property: 'user',
autoFetch: true
},
endpoints: {
login: { url: '/sign/login', method: 'post' },
logout: { url: '/sign/logout', method: 'post' },
user: { url: '/sign/user-login', method: 'get' }
}
}
}
}
base index ('/')
<template>
<div class="container">
<div>
<Logo />
<h1 class="title">Learn Nuxt</h1>
<div class="links">
<a href="https://nuxtjs.org/" target="_blank" rel="noopener noreferrer" class="button--green">
Documentation
</a>
<a
href="https://github.com/nuxt/nuxt.js"
target="_blank"
rel="noopener noreferrer"
class="button--grey"
>
GitHub
</a>
</div>
</div>
</div>
</template>
<script>
import { mapGetters } from 'vuex'
export default {
computed: {
...mapGetters(['isAuthenticated', 'loggedInUser']),
},
}
</script>
In your vuex store, the state parameter in your getter only has access to local state. You can't access the auth state the way you tried.
In a vuex module, a getter gets 4 arguments, namely local state, local getters, root state and root getters. So if you would rewrite your getters like this it would probably work:
export const getters = {
isAuthenticated(state, getters, rootState) {
return rootState.auth.loggedIn
},
loggedInUser(state, getters, rootState) {
return rootState.auth.user
}}
}
But I still think it is a bit redundant doing it like that. I would replace isAuthenticated with this.$auth.loggedIn in your default layout. The nuxt-auth module globally injects the $auth instance, meaning that you can access it anywhere using this.$auth.
I had same problem after authorizing user and redirect user to the home page.
After many tries and doing many works, the right config of auth in nuxt.config.js seemed like this:
auth: {
strategies: {
local: {
scheme: 'refresh',
token: {
property: 'access_token',
tokenType: false,
maxAge: 60 * 60
},
refreshToken: {
property: 'refresh_token',
data: '',
maxAge: 60 * 60
},
endpoints: {
login: {
url: 'url/of/token',
method: 'urlMethod'
},
refresh: {
url: 'url/of/refreshToken',
method: 'urlMethod'
},
logout: false,
user: false
}
}
},
cookie: false,
redirect: {
login: '/login/page',
logout: '/login/page',
callback: false,
home: '/home/page'
}
},
Note that I didn't have any refreshToken property, but I should set it as empty string in config to be able to work with nuxt/auth!
Hope I could help
I'm loading notifications from an api using get request, the data is there i can see it in the console but it's not displayed in the view here is my code :
<!-- Header -->
<li class="dropdown-menu-header">
<div class="dropdown-header d-flex">
<h4 class="notification-title mb-0 mr-auto">
Notifications
</h4>
<b-badge pill variant="light-primary">
{{ notifications.length }} New
</b-badge>
</div>
</li>
<!-- Notifications -->
<vue-perfect-scrollbar v-once :settings="perfectScrollbarSettings" class="scrollable-container media-list scroll-area" tagname="li">
<!-- Account Notification -->
<b-link v-for="notification in notifications" :key="notification.id">
<b-media>
<template #aside>
<b-avatar size="32" :src="require('#/assets/images/avatars/6-small.png')" :text="notification.id" :variant="notification.type" />
</template>
<p class="media-heading">
<span class="font-weight-bolder">
{{ notification.data.message }}
</span>
</p>
<small class="notification-text">{{ notification.created_at | formatDate}}</small>
</b-media>
</b-link>
</vue-perfect-scrollbar>
here is the method :
data() {
return {
notifications: []
}
},
mounted() {
this.getNotifications();
},
methods: {
getNotifications() {
axios.get(apiHost + '/notification')
.then((response) => {
for (let i = 0; i < response.data.length; i++) {
this.notifications.push(response.data[i])
}
console.log(this.notifications)
})
.catch(resonse => {
console.log(resonse);
})
},
},
I just get the length of the array but i can t display the data:
please try just this:
data() {
return {
notifications: []
}
},
async mounted() {
await this.getNotifications();
},
methods: {
async getNotifications() {
await axios.get(apiHost + '/notification')
.then((response) => {
this.notifications = response.data
}
})
.catch(resonse => {
console.log(resonse);
})
},
},
otherwise please show us the response from the api, if you like mocked of course
I have a navbar component that contains 2 buttons "Logout" and "Dashboard" that are rendered only if the user is authenticated. (using v-if).
However when the user click on the Logout button, the navbar is not reloaded and so the buttons stay visible until you reload the page. How do I set my v-if condition so that when the value of the v-if change, also the components (divs) update?
My Navbar
<!-- ... -->
<template slot="end">
<b-navbar-item tag="div">
<div class="buttons">
<a v-if="userToken" class="button is-primary" style='padding:4px; margin-right:0;'>
<b-button size="is-normal"
type="is-primary"
icon-right="close"
outlined
inverted
style="margin-bottom: 0;"
#click="logout">
Logout
</b-button>
</a>
<a v-if="userToken" class="button is-primary" style='padding:4px; margin-left:0;'>
<b-button size="is-normal"
type="is-success"
icon-right="account-circle-outline"
style="margin-bottom: 0;"
#click="goToDashboard">
Dashboard
</b-button>
</a>
<a v-else class="button is-primary">
<b-icon icon="account-circle-outline" size="is-medium"> </b-icon>
</a>
</div>
</b-navbar-item>
</template>
</b-navbar>
</template>
<script>
export default {
data () {
return {
userToken : '',
},
methods: {
getUserToken() {
let token = this.$cookies.get('userToken')
if (token) {
this.userToken = token
this.$router.push('user_dashboard')
}
},
logout() {
this.$cookies.remove('userToken')
this.userToken = ''
}
},
mounted() {
this.getUserToken()
},
// ...
</script>
Ok I'm really sorry, I eventually solved the issue by making those changes:
methods: {
getUserToken() {
let token = this.$cookies.get('userToken')
if (token) {
this.userToken = token
this.$router.push('user_dashboard')
} else {
this.userToken = ''
}
},
logout() {
this.$cookies.remove('userToken')
this.getUserToken()
}
},
mounted() {
this.getUserToken()
},
Good afternoon, please tell me. I am training now using Vuex and I cannot transfer the post from one component to another. I have a component Pagination, where all the posts and the history component are stored where and should send the first 5 posts that I click on to visit them. That is, it should work approximately as a history of viewing posts. I wrote some code here, but my posts are not displayed, tell me what I'm doing wrong and how to fix it.
Component code where all posts are stored:
<template>
<div class = "app">
<ul>
<li v-for="(post, index) in paginatedData" class="post" :key="index">
<router-link :to="{ name: 'detail', params: {id: post.id, title: post.title, body: post.body} }" #click="addPostToHistoryComp(post.id, post.title, post.body)">
<img src="src/assets/nature.jpg">
<p class="boldText"> {{ post.title }}</p>
</router-link>
<p> {{ post.body }}</p>
</li>
</ul>
<div class="allpagination">
<button type="button" #click="page -=1" v-if="page > 0" class="prev"><<</button>
<div class="pagin">
<button class="item"
v-for="n in evenPosts"
:key="n.id"
v-bind:class="{'selected': current === n.id}"
#click="page=n-1">{{ n }} </button>
</div>
<button type="button" #click="page +=1" class="next" v-if="page < evenPosts-1">>></button>
</div>
</div>
</template>
<script>
import {mapState} from 'vuex'
export default {
name: 'app',
data () {
return {
current: null,
page: 0,
visiblePostID: '',
}
},
mounted(){
this.$store.dispatch('loadPosts')
},
computed: {
posts(){
return this.$store.state.posts
},
search(){
return this.$store.state.sSearch
},
evenPosts: function(posts){
return Math.ceil(this.posts.length/6);
},
paginatedData() {
const start = this.page * 6;
const end = start + 6;
return this.filteredPosts.slice(start, end);
},
filteredPosts() {
return this.posts.filter((post) => {
return post.title.match(this.search);
});
},
},
methods: {
addPostToHistoryComp(val){
this.$store.dispatch('transforPostToHistoryComp', { // как вызвать actions с объект с параметром
pTitle: val.post.title,
pBody: val.post.body,
pId: val.post.id
})
},
}
}
</script>
The code of the History component where the last 5 posts that were opened should be displayed:
<template>
<div class="history">
<ul>
<li v-for="(historyPost, index) in historyPosts" class="post" :key="index">
<img src="src/assets/nature.jpg">
<p class="boldText"> {{ post.title }}</p>
<p> {{ post.body }}</p>
</li>
</ul>
</div>
</template>
<script>
export default{
computed: {
historyPosts(){
return this.$store.state.historyPosts
},
},
}
</script>
And the code of my story (Vuex):
export default new vuex.Store({
state: {
posts: [],
sSearch: '',
title: '',
body: '',
id: Number,
historyPosts: []
},
actions: {
loadPosts ({commit}) {
axios.get('http://jsonplaceholder.typicode.com/posts').then(response => {
let posts = response.data
commit('SET_POSTS', posts)
}).catch(error => {
console.log(error);
})
},
transforTitleAndBody({commit}, payload){ // мутация которая изменяет сосотаяние в sSearch
const todo = {
title: payload.sTitle,
body: payload.sBody,
id: payload.sId
}
axios.post('http://jsonplaceholder.typicode.com/posts', todo).then(_ => {
commit('ADD_TODO', todo)
}).catch(function (error) {
console.log(error);
})
},
transforPostToHistoryComp({commit}, payload){ // мутация которая изменяет сосотаяние в sSearch
const todohistory = {
title: payload.pTitle,
body: payload.pBody,
id: payload.pId
}
commit('ADD_TODO_HISTORY', todohistory)
}
},
mutations: {
SET_POSTS(state, posts) {
state.posts = posts
},
transforSearch(state, payload){ // мутация которая изменяет сосотаяние в sSearch
state.sSearch = payload
},
ADD_TODO (state, todoObject) {
state.posts.unshift(todoObject)
},
ADD_TODO_HISTORY (state, todohistoryObject) {
state.historyPosts.unshift(todohistoryObject)
},
},
})
I found what happening. You have some erros on code of the file Pagination.vue
You was putting #click under <router-link>, that doesn't work because router link change the page with preventing effect any other event before leave.
I made some changes on template and script. I think will work.
<template>
<div class="app">
<ul>
<template v-for="(post, index) in paginatedData">
<li class="post" :key="index" #click="addPostToHistoryComp(post)">
<img src="src/assets/nature.jpg">
<p class="boldText">{{ post.title }}</p>
<p>{{ post.body }}</p>
</li>
</template>
</ul>
<div class="allpagination">
<button type="button" #click="page -=1" v-if="page > 0" class="prev"><<</button>
<div class="pagin">
<button
class="item"
v-for="n in evenPosts"
:key="n.id"
v-bind:class="{'selected': current === n.id}"
#click="page=n-1"
>{{ n }}</button>
</div>
<button type="button" #click="page +=1" class="next" v-if="page < evenPosts-1">>></button>
</div>
</div>
</template>
<script>
import { mapState } from "vuex";
export default {
name: "app",
data() {
return {
current: null,
page: 0,
visiblePostID: ""
};
},
mounted() {
this.$store.dispatch("loadPosts");
},
computed: {
posts() {
return this.$store.state.posts;
},
search() {
return this.$store.state.sSearch;
},
evenPosts: function(posts) {
return Math.ceil(this.posts.length / 6);
},
paginatedData() {
const start = this.page * 6;
const end = start + 6;
return this.filteredPosts.slice(start, end);
},
filteredPosts() {
return this.posts.filter(post => {
return post.title.match(this.search);
});
}
},
methods: {
addPostToHistoryComp(post) {
this.$store.dispatch("transforPostToHistoryComp", {
pTitle: post.title,
pBody: post.body,
pId: post.id
});
this.$router.push({
name: "detail",
params: { id: post.id, title: post.title, body: post.body }
});
}
}
};
</script>
I use vuex for state management and authenticate users with
firebase
I use vuex-persisted state to save the state in cookies
In my vuex store I manage my userdata(user name , logged in status) as below
my store.js
/all imports here
export const store = new Vuex.Store({
state : {
user: {
loggedIn: false,
userName: 'Guest'
}
},
getters : {
g_user: state => {
return state.user;
}
},
mutations : {
m_logInUser: (state, userName) => {
state.user.loggedIn = true;
state.user.userName = userName;
},
m_loggedOut: (state) => {
state.user.loggedIn = false;
state.user.userName = 'Guest';
}
},
actions : {
a_logInUser: ({state, commit}, userInput) => {
//call to the API and on success commit m_logInUser mutation
},
a_loggedOut: ({commit}) => {
//call to the API and on success commit m_loggedOut mutation
}
},
plugins: [
createPersistedState({
paths: ['authStore.user'],
getState: (key) => Cookie.getJSON(key),
setState: (key, state) => Cookie.set(key, state, { expires: 3, secure: false })
})
]
});
now the problem I am facing
when I open the app in two different tabs and login the user in 1st tab , the user logs in which now hides the login buton and shows logout button and shows the username
but in the 2nd tab its still showing the login button , but when i console.log for the user, it shows logged in and also the username
here is my header.vue component
<template>
<nav class="navbar navbar-default">
<div class="container-fluid">
<div class="navbar-header">
<router-link to="/" tag="a" class="navbar-brand">Brand</router-link>
</div>
<!-- Collect the nav links, forms, and other content for toggling -->
<div class="collapse navbar-collapse" id="bs-example-navbar-collapse-1">
<ul class="nav navbar-nav">
<li #click="testmethod"><a>cuser</a></li>
<router-link to="/statuses" active-class="active" tag="li"><a>Status</a></router-link>
<router-link to="/users" active-class="active" tag="li"><a>Users</a></router-link>
</ul>
<ul class="nav navbar-nav navbar-right" v-if="!g_user.loggedIn">
<router-link to="/signup" active-class="active" tag="li"><a>Signup</a></router-link>
<router-link :to="{name: 'login'}" active-class="active" tag="li"><a>Login</a></router-link>
</ul>
<ul class="nav navbar-nav navbar-right" v-else>
<router-link to="/post" tag="li"><a><button class="btn btn-info">POST</button></a></router-link>
<router-link to="/current" active-class="active" tag="li"><a>{{ g_user.userName }}</a></router-link>
<li #click="logOut"><a>Log out</a></li>
</ul>
</div><!-- /.navbar-collapse -->
</div><!-- /.container-fluid -->
</nav>
</template>
<script>
import { mapGetters } from 'vuex'
export default{
methods: {
logOut(){
this.$store.dispatch('a_loggedOut');
},
testmethod(){
var user = this.$firebase.auth().currentUser;
console.log(user);
console.log(user.email);
}
},
computed: {
...mapGetters([
'g_user'
])
}
}
</script>
You can watch your Vuex state:
mounted() {
this.$store.watch(
function(state) {
return state.g_user.loggedIn;
},
function(value) {
if (value === true) {
console.log('user is logged in');
// do your logic here, setup loggedin behavior hooks. For example call login() function which should first check if the user is already logged in
}
},
{
immediate: true
}
);
},