v-if with computed property is triggering just after reload of page - vue.js

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

Issue with nuxt/auth

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

How to display loaded data after page refresh in vue, the data is displayed in the console but not in theview

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

Nuxtjs component not hotreloading on v-if condition change

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()
},

How to transfer post from one component to another?

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>

Computed property not updaing UI in different tabs

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
}
);
},