I'm trying to make a component for a login view. My app is really simple right now as I'm trying to learn Vue/Vuex.
In the sign in component, I want to check if the email is valid, using a computed value.
var emailRE = /^(([^<>()[\]\\.,;:\s#\"]+(\.[^<>()[\]\\.,;:\s#\"]+)*)|(\".+\"))#((\[[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\])|(([a-zA-Z\-0-9]+\.)+[a-zA-Z]{2,}))$/;
export default {
name: "SignIn",
data: () => {
return {
email: "",
password: ""
};
},
computed: {
isValidEmail: () => {
return emailRE.test(this.email);
}
},
methods: {
signIn() {
if (this.isValidEmail) {
this.$store.dispatch("signIn", {
email: this.email,
password: this.password
});
}
}
}
};
However, the isValidEmail function throws an error in the console:
Uncaught TypeError: Cannot read property 'email' of undefined
Why can't my computed value read the this.email?
PS: I had to use data as a function according to the guidelines.
From the comments:
Actually, VSCode won't complain as there is no syntax error in your
code but its a wrong usage of the arrow function. In fact Vuejs docs
warns us against using arrow functions in the vue components
properties vuejs.org/v2/guide/instance.html#Instance-Lifecycle-Hooks .
For more on arrow function and 'this' usage check this article.
medium.freecodecamp.org/… . Its a 5 minute read article very plainly
written with nice example.
This now works:
var emailRE = /^(([^<>()[\]\\.,;:\s#\"]+(\.[^<>()[\]\\.,;:\s#\"]+)*)|(\".+\"))#((\[[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\])|(([a-zA-Z\-0-9]+\.)+[a-zA-Z]{2,}))$/;
export default {
name: "SignIn",
data () {
return {
email: "",
password: ""
};
},
computed: {
isValidEmail () {
return emailRE.test(this.email);
}
},
methods: {
signIn () {
if (this.isValidEmail) {
this.$store.dispatch("signIn", {
email: this.email,
password: this.password
});
}
}
}
};
Related
I'm using nuxt.js, after I send a login request with email and password to the backend I get a response which contains a message, token and user informations, how can I access user informations in the response and save it inside some state in store.js after a successful login?
I wanted to save user object in user state down in store/index.js using an action saveUserAction which might be dispatched after a successful login, i dont know if thats right or not, any advise would be very helpful
Response
{
"message":"success",
"token":"eyJ0eXAiOiJKV1QiLCJhbGciOiJSUzI1NiJ9.eyJhdWQiOiIxIiwianRpIjoiNzFkYjA1MWM2MTYxMmE4YzAyNWI2YjU3N2xMzJiNzJjMjI0MzRlY2IzNzYwNTg2N2NjOWQ5ZWEwY2MiMJM3uYEiZ8GSlPlQhIctVErO2KzwXOBxifWWoM7et_qT-mgvfsk3ljwiQF9iPQw-WeekBx8J8lcmxDLESa3tfE1Re1Xk2flkcBLmiI4JN2YHh08U1U",
"user":{
"id":1,
"role_id":4587,
"firstname":"Hans",
"lastname":"newman",
"email":"newman#gmail.com",
"email_verified_at":null,
"phone":"89498",
"skype":"gdgdfg",
"birthdate":"2021-05-02",
"address":"asdfaf",
"postalcode":14984,
"city":"jisf",
"country":"isfisf",
"status":"mfof",
"created_at":"2021-06-16T09:33:08.000000Z",
"updated_at":"2021-06-16T09:39:41.000000Z",
"image":"1623835988-carlsen.png",
"description":"sfdgg",
"geo_lat":5.5,
"geo_lng":8.1
}
}
login.vue
<script>
import { mapActions } from 'vuex'
export default {
data() {
return {
auth: false,
email: '',
password: '',
}
},
methods: {
async login() {
const succesfulLogin = await this.$auth.loginWith('local', {
data: {
email: this.email,
password: this.password,
},
})
if (succesfulLogin) {
await this.$auth.setUser({
email: this.email,
password: this.password,
})
this.$router.push('/profile')
}
},
},
}
</script>
store/index.js
export const state = () => ({
user:{}
})
export const mutations = {
saveUser(state, payload) {
state.user=payload;
}
}
export const actions = {
saveUserAction({commit}, UserObject){
commit('saveUser');
}
}
Go to your vue devtools, vuex tab and look for auth, it should already be available. This answer may help you during your debugging: https://stackoverflow.com/a/68081536/8816585
Since you do have your user object in the response, this kind of configuration should do it, as shown in the documentation. No need to make some other vuex actions.
auth: {
strategies: {
local: {
token: {
property: 'token',
global: true,
},
user: {
property: 'user', // the name of your object in your backend response payload
},
endpoints: {
[...]
}
}
}
}
I added middlewares to default.vue component:
export default {
components: {
TheHeader
},
middleware: ['auth'],
}
My auth.js:
export default function ({ app, store }) {
if (app.$cookies.get('AUTH_TOKEN')) {
var AUTH_TOKEN = app.$cookies.get('AUTH_TOKEN')
app.$axios.$post('https://example.com/api', {
email: Buffer.from(AUTH_TOKEN[0], 'base64').toString(),
password: Buffer.from(AUTH_TOKEN[1], 'base64').toString(),
}).then(response => {
store.dispatch('changeAuthStatus', {
authStatus: true,
userData: {
id: response.data.id,
login: response.data.login,
email: response.data.email,
firstName: response.data.first_name,
lastName: response.data.last_name,
}
})
})
}
}
So I can't understand why my middlewares don't load when the page is reloaded or with direct access to the page. Also mode: 'universal' and ssr: true are set in nuxt.config.js
Here is the documentation for the middlewares: https://nuxtjs.org/docs/2.x/directory-structure/middleware/
Few steps to have a working middleware:
use it only in a page (/pages/hello.vue) or layout (/layouts/MyFancyLayout.vue)
put the middleware in the proper directory (/middleware/test.js)
call it properly in the .vue file like middleware: 'test'
You can also try to debug and see if something like this works
export default {
middleware() {
console.log('working!')
}
}
It is working on client transitions and should be good on initial page load aswell.
As a more accurate way, you should do this in the Vuex Store using the 'context' attribute.
middleware/auth.js
export default function(context) {
if (process.client) {
context.store.dispatch('initAuth', null);
}
context.store.dispatch('initAuth', context.req);
}
store/index.js
import Cookie from 'js-cookie'
store/index.js
actions:{
initAuth(vuexContext,state){
let token;
let jwtCookie;
if (req) {
if (!req.headers.cookie) {
return;
}
jwtCookie = req.headers.cookie
.split(";")
.find(c => c.trim().startsWith("jwt="));
if (!jwtCookie) {
return;
}
token = jwtCookie.split('=')[1];
} else {
token = localStorage.getItem('token');
}
vuexContext.commit('setToken', token);
return $axios.post('https://example.com/api', {
email: Buffer.from(AUTH_TOKEN[0], 'base64').toString(),
password: Buffer.from(AUTH_TOKEN[1], 'base64').toString(),
}).then(response => {
vuexContext.commit('changeAuthStatus', {
authStatus: true,
userData: {
id: response.data.id,
login: response.data.login,
email: response.data.email,
firstName: response.data.first_name,
lastName: response.data.last_name,
}
})
})
}
}
this way it will work smoothly and understandably
I have the following apollo query setup. I want to pass the username dynamically but this.username is not recognized.
My code:
export default {
data () {
return {
username: ''
};
},
beforeCreate () {
this.$Auth
.currentAuthenticatedUser()
.then((userProfile) => {
this.username = userProfile.username;
})
.catch(() => this.$router.push({ name: 'auth' }));
},
apollo: {
services: {
query: gql(servicesByUser),
variables: {
username: this.username
},
update: (data) => {
console.log('apollo:services', data);
return data.servicesByUser.items;
},
},
},
};
The below-hardcoded setup works:
variables: {
username: "user-a"
},
This setup does not work:
variables: {
username: this.username
},
Error:
TypeError: Cannot read property 'username' of undefined
at Module../node_modules/babel-loader/lib/index.js?!./node_modules/#quasar/app/lib/webpack/loader.auto-import.js?
I have spent a few hours on it, still not able to figure the issue! Am I missing anything? Any help is much appreciated!
variables should be a function in order for this to be defined, as shown in the docs:
apollo: {
services: {
...
variables () {
return {
username: this.username,
}
},
},
},
I am new to Vue.js. I have recently learned Vuex and trying to implement in my project.
I am calling calling an action dispatch from my dashboard component. And calling ...mapGetter in message component computed section. And I want to debug the data that I am getting.
I already searched my problem. But couldn't find it. What I learned I can't use console.log() in computed. I have to use debugger. But when I am using debugger it's saying debugger is a reserved word.
in my store:
state: {
conversationThreads: [],
conversation: [],
users: [],
},
getters: {
conversation: state => {
return state.conversation;
}
},
mutations: {
[MUTATION_TYPES.SET_CONVERSATION](state, conversationThread){
state.conversation= conversationThread;
}
},
actions: {
getConversationByID: ({ commit }, conversationInfo) => {
console.log("conversationData: ", conversationInfo)
axios.get("https://some_API" + conversationInfo.id)
.then(response => {
let conversationThread = response.data.messages.data.map(res => ({
name: res.from.name,
msg: res.message
}));
commit(MUTATION_TYPES.SET_CONVERSATION, conversationThread);
})
.catch(error => console.log(error))
}
}
in my dashboard component:
methods: {
selectedDiv: function(conversationInfo, event){
this.$store.dispatch('getConversationByID', conversationInfo)
}
}
in my message component:
computed: {
...mapGetters([
"conversation"
]),
debugger
},
You can get similar functionality without using mapGetter, below is example.
computed: {
yourProperty(){
const profile = this.$store.getters.profile;
console.log('profile: ', profile); //Debug
return profile;
}
},
Another option is to put a watch on computed property.
computed: {
...mapGetters(["profile"]),
},
watch: {
profile: {
handler(profile) {
console.log('profile: ', profile); //Debug
},
deep: true
}
},
Here deep true option is used to watch on key updates of profile object. If deep true is not provided then watch will get called only when profile getter is reassigned with new object.
I'm new to vue (started using vue 2) I'm using Store (vuex) and I'm trying to acheive something.
basically I managed to install the vue-auth plugin : I have this.$auth that I can call from within .vue files.
Now using the store I wanna call the userLogin function by dispatching the call like this from a vue file :
<script>
export default {
computed: {
comparePasswords() {
return this.password === this.passwordConfirm
? true
: "Passwords don't match";
}
},
methods: {
userSignUp() {
if (this.comparePasswords !== true) {
return;
}
this.$store.dispatch("userSignUp", {
email: this.email,
password: this.password
});
}
},
data() {
return {
email: "",
password: "",
passwordConfirm: ""
};
}
};
</script>
in the store/index I'm trying to access the 'this.$auth' I do understand is some kind of context switching but I don't know how to access the vue app instance. :
import Vue from 'vue'
import Vuex from 'vuex'
Vue.use(Vuex)
let app = this
export const store = new Vuex.Store({
state: {
appTitle: 'LiveScale Dashboard',
user: null,
error: null,
loading: false
},
mutations: {
setUser(state, payload) {
state.user = payload
},
setError(state, payload) {
state.error = payload
},
setLoading(state, payload) {
state.loading = payload
}
},
actions: {
userLogin({ commit }, payload) {
commit('setLoading', true)
var redirect = this.$auth.redirect(); // THIS IS WRONG.
this.$auth.login({ // THIS IS WRONG.
body: payload, // Vue-resource
data: payload, // Axios
rememberMe: this.data.rememberMe,
redirect: { name: redirect ? redirect.from.name : 'account' },
fetchUser: this.data.fetchUser
})
.then(() => {
commit('setUser', this.context)
commit('setLoading', false)
router.push('/home')
}, (res) => {
console.log('error ' + this.context);
commit('setError', res.data)
commit('setLoading', false)
});
},
userSignUp({ commit }, payload) {
// ...
}
},
getters: {}
})
Thanks for your help
try using Vue.$auth in index.js it should work
The idea (so far) is to pass the instance as an argument to the function as follows :
this.$store.dispatch("userSignUp", {
email: this.email,
password: this.password,
auth: this.$auth //added this line
});
and then in the store -> actions , payload.auth will contain my auth plugin :
userLogin({ commit }, payload) {
commit('setLoading', true)
var redirect = payload.auth.redirect();
payload.auth.login({
body: payload, // Vue-resource
data: payload, // Axios
rememberMe: this.data.rememberMe,
redirect: { name: redirect ? redirect.from.name : 'account' },
fetchUser: this.data.fetchUser
})
.then(() => {
commit('setUser', this.context)
commit('setLoading', false)
router.push('/home')
}, (res) => {
console.log('error ' + this.context);
commit('setError', res.data)
commit('setLoading', false)
});
},
I don't know if it's the best practice or not, but this is how I managed to do it. Please feel free to suggest anything.