Vue.js Cannot read properties of undefined (reading 'router') error - vue.js

I'm new to Vue.js and I have created one simple form for the user and storing data using API.
On submit I'm calling this function:
setup(props, { emit }) {
const blankData = {
customer: '',
template: '',
rate: '',
property_from: '',
property_to: '',
move_date: '',
num_days: '',
token: '',
details: '',
customer_options: [],
template_options: [],
rate_options: [],
property_from_options: [],
property_to_options: [],
}
const userData = ref(JSON.parse(JSON.stringify(blankData)))
const resetuserData = () => {
userData.value = JSON.parse(JSON.stringify(blankData))
}
const toast = useToast()
const onSubmit = () => {
store.dispatch('app-user/addUser', userData.value)
.then(
response => {
if (response.status === 1) {
this.$router.push({ name: 'edit-user', params: { id: 10 } })
}
toast({
component: ToastificationContent,
props: {
title: response.message,
icon: response.toastIcon,
variant: response.toastVariant,
},
})
},
error => {
console.log(error)
},
)
}
const {
refFormObserver,
getValidationState,
resetForm,
} = formValidation(resetuserData)
return {
userData,
onSubmit,
refFormObserver,
getValidationState,
resetForm,
}
},
And trying to redirect the user to the edit page after user creation but I'm getting this error and not redirecting:
Uncaught (in promise) TypeError: Cannot read properties of undefined (reading 'router')
I have tried with this stackoverflow answer but getting same error:
const onSubmit = () => {
const self = this
store.dispatch('app-user/addUser', userData.value)
.then(
response => {
if (response.status === 1) {
self.$router.push({ name: 'edit-user', params: { id: 10 } })
}
},
error => {
console.log(error)
},
)
}
Any idea what I'm doing wrong in my code?

You're using Vue 3 and a setup function; there is no this in a setup function.
See Accessing the Router and current Route inside setup.
Untested, but probably something like this will work:
setup() {
const router = useRouter()
const onSubmit = () => {
// ... code omitted ...
router.push({ name: 'edit-user', params: { id: 10 } })
}
return {
onSetup,
// other stuff...
}
}

I think this might be help
router with composition api
https://next.router.vuejs.org/guide/advanced/composition-api.html

Related

how solve Avoided redundant navigation to current location: "/login". in vue?

Hi everybody i'm trying to make login page and redirect to home page ('/')
When i'm logging i haven't errors in console i can see the error using vue devtools
ERROR VUE DEV TOOL
End of navigation
/login
02:27:19.124
guard:afterEach
failure:Avoided redundant navigation to current location: "/login".
status:❌
from:/login
fullPath:"/login"
path:"/login"
query:Object (empty)
hash:""
name:"login"
params:Object (empty)
matched:Array[1]
meta:Object (empty)
redirectedFrom:undefined
href:"/login"
to:/login
fullPath:"/login"
hash:""
query:Object (empty)
name:"login"
path:"/login"
params:Object (empty)
matched:Array[1]
meta:Object (empty)
redirectedFrom:Object
href:"/login"
this is my login's method
methods:{
async submitForm(user){
const userForm=new FormData();
userForm.append("username", this.username);
userForm.append("password", this.password);
await this.$store.dispatch("auth/login", userForm).then(
()=>{
const user = localStorage.getItem('user')
console.log(user) //to check if i logged, in console get undefined but if try localStorage.getItem('user') i got the user.
this.$router.push('/')
}),
(error)=>{
console.log(error)
}
}
}
ROUTES
const router = createRouter({
history: createWebHistory(),
scrollBehavior() {
return { top: 0 }
},
routes,
})
{
path: '/',
name: 'dashboard',
component: () => import('#/views/Dashboard.vue'),
children: [
{
path: '',
name: 'home',
component: () => import('#/views/dashboard/Home.vue'),
},
....
router.beforeEach((to, from, next) => {
const publicPages = ['/login'];
const authRequired = !publicPages.includes(to.path);
const loggedIn = localStorage.getItem('user');
// trying to access a restricted page + not logged in
// redirect to login page
if (authRequired && !loggedIn) {
next('/login');
} else {
next();
}
});
auth.service
class AuthService {
login(user) {
let dator={
access_token: '',
user:{}
}
console.log('AUTHSERVICE-->\n'+user)
return axios
.post(API_URL + 'login/access-token', user)
.then(response => {
console.log(response.data.access_token)
if (response.data.access_token) {
dator.access_token=response.data.access_token
localStorage.setItem('token', JSON.stringify(dator.access_token))
axios.get(API_URL + 'users/me/', { headers: authHeader() })
.then(response =>{
localStorage.setItem('user', JSON.stringify(response.data))
dator.user=response.data
})
}
return dator;
});
}
auth.module VUEX
import AuthService from '../services/auth.service';
const token = JSON.parse(localStorage.getItem('token'));
const user = JSON.parse(localStorage.getItem('user'));
const initialState = token && user
? { status: { loggedIn: true }, token,user }
: { status: { loggedIn: false }, token:null, user: null };
export const auth = {
namespaced: true,
state: initialState,
actions: {
login({ commit }, userForm) {
console.log(userForm)
return AuthService.login(userForm).then(
datologin => {
console.log('datologin',datologin)
commit('loginSuccess', datologin);
return Promise.resolve(datologin);
},
error => {
commit('loginFailure');
return Promise.reject(error);
}
);
},
if after login i force the '/' in the browser the page work. So i don't know where is my bad.
Sorry for noob error. The problem was in second request with axios so i refactor this part and now work
async asyncLogin(user){
let uservuex={
access_token: '',
user:{}
}
try{
const token = await axios.post(API_URL + 'login/access-token', user)
uservuex.access_token = await token.data.access_token
localStorage.setItem('token', JSON.stringify(uservuex.access_token))
const me = await axios.get(API_URL + 'users/me/', { headers: authHeader() })
uservuex.user= await me.data
localStorage.setItem('user', JSON.stringify(uservuex.user))
}catch(error){
console.log(error)
}
return uservuex
}

How can I update the comments without refreshing it?

First, I'm using vuex and axios.
store: commentService.js
components:
CommentBox.vue (Top components)
CommentEnter.vue (Sub components)
This is the logic of the code I wrote.
In the store called commentService.js, there are mutations called commentUpdate.
And There are actions called postComment and getComment.
At this time, In the component called CommentBox dispatches getComment with async created().
Then, in getComment, commentUpdate is commited and executed.
CommentUpdate creates an array of comments inquired by getComment and stores them in a state called commentList.
Then I'll get a commentList with "computed".
CommentEnter, a sub-component, uses the commentList registered as compounded in the CommentBox as a prop.
The code below is commentService.js.
import axios from 'axios'
export default {
namespaced: true,
state: () => ({
comment:'',
commentList: []
}),
mutations: {
commentUpdate(state, payload) {
Object.keys(payload).forEach(key => {
state[key] = payload[key]
})
}
},
actions: {
postComment(state, payload) {
const {id} = payload
axios.post(`http://??.???.???.???:????/api/books/${id}/comments`, {
comment: this.state.comment,
starRate: this.state.starRate
}, {
headers: {
Authorization: `Bearer ` + localStorage.getItem('user-token')
}
})
.then((res) => {
console.log(res)
this.state.comment = ''
this.state.starRate = ''
)
.catch((err) => {
alert('댓글은 한 책당 한 번만 작성할 수 있습니다.')
console.log(err)
this.state.comment = ''
this.state.starRate = ''
})
},
async getComment({commit}, payload) {
const {id} = payload
axios.get(`http://??.???.???.???:????/api/books/${id}/comments`)
.then((res) => {
console.log(res)
const { comment } = res.data.commentMap
commit('commentUpdate', {
commentList: comment
})
})
.catch((err) => {
console.log(err)
commit('commentUpdate', {
commentList: {}
})
})
}
}
}
The code below is CommentBox.vue
computed: {
commentList() {
return this.$store.state.commentService.commentList
}
},
methods: {
async newComment() {
if(this.$store.state.loginService.UserInfoObj.id === '') {
alert('로그인 후 이용할 수 있습니다.')
return
}
this.$store.dispatch('commentService/postComment', {
id: this.$route.params.id,
comment: this.$store.state.comment,
starRate: this.$store.state.starRate
})
}
},
async created() {
this.$store.dispatch('commentService/getComment', {
id: this.$route.params.id
})
}
The code below is CommentEnter.vue
created() {
this.userComment = this.comment
},
props: {
comment: {
type: Object,
default: () => {}
}
},
I asked for a lot of advice.
There were many comments asking for an axios get request after the axios post request was successful.
In fact, I requested an axios get within .then() of the axios post, and the network tab confirmed that the get request occurred normally after the post request.
But it's still not seen immediately when I register a new comment.
I can only see new comments when I refresh it.
How can I make a new comment appear on the screen right away when I register it?
Can't you just call getComment when postComment is finished?
methods: {
async newComment() {
if(this.$store.state.loginService.UserInfoObj.id === '') {
alert('로그인 후 이용할 수 있습니다.')
return
}
this.$store.dispatch('commentService/postComment', {
id: this.$route.params.id,
comment: this.$store.state.comment,
starRate: this.$store.state.starRate
}).then(function() {
this.$store.dispatch('commentService/getComment', {
id: this.$route.params.id
})
})
}
},
}
Or since you're using async:
methods: {
async newComment() {
if(this.$store.state.loginService.UserInfoObj.id === '') {
alert('로그인 후 이용할 수 있습니다.')
return
}
await this.$store.dispatch('commentService/postComment', {
id: this.$route.params.id,
comment: this.$store.state.comment,
starRate: this.$store.state.starRate
})
this.$store.dispatch('commentService/getComment', {
id: this.$route.params.id
})
}
},
}

Nuxt asyncData result is undefined if using global mixin head() method

I'm would like to get titles for my pages dynamically in Nuxt.js in one place.
For that I've created a plugin, which creates global mixin which requests title from server for every page. I'm using asyncData for that and put the response into storage, because SSR is important here.
To show the title on the page I'm using Nuxt head() method and store getter, but it always returns undefined.
If I place this getter on every page it works well, but I would like to define it only once in the plugin.
Is that a Nuxt bug or I'm doing something wrong?
Here's the plugin I wrote:
import Vue from 'vue'
import { mapGetters } from "vuex";
Vue.mixin({
async asyncData({ context, route, store, error }) {
const meta = await store.dispatch('pageMeta/setMetaFromServer', { path: route.path })
return {
pageMetaTitle: meta
}
},
...mapGetters('pageMeta', ['getTitle']),
head() {
return {
title: this.getTitle, // undefined
// title: this.pageMetaTitle - still undefined
};
},
})
I would like to set title in plugin correctly, now it's undefined
Update:
Kinda solved it by using getter and head() in global layout:
computed: {
...mapGetters('pageMeta', ['getTitle']),
}
head() {
return {
title: this.getTitle,
};
},
But still is there an option to use it only in the plugin?
Update 2
Here's the code of setMetaFromServer action
import SeoPagesConnector from '../../connectors/seoPages/v1/seoPagesConnector';
const routesMeta = [
{
path: '/private/kredity',
dynamic: true,
data: {
title: 'TEST 1',
}
},
{
path: '/private/kreditnye-karty',
dynamic: false,
data: {
title: 'TEST'
}
}
];
const initialState = () => ({
title: 'Юником 24',
description: '',
h1: '',
h2: '',
h3: '',
h4: '',
h5: '',
h6: '',
content: '',
meta_robots_content: '',
og_description: '',
og_image: '',
og_title: '',
url: '',
url_canonical: '',
});
export default {
state: initialState,
namespaced: true,
getters: {
getTitle: state => state.title,
getDescription: state => state.description,
getH1: state => state.h1,
},
mutations: {
SET_META_FIELDS(state, { data }) {
if (data) {
Object.entries(data).forEach(([key, value]) => {
state[key] = value;
})
}
},
},
actions: {
async setMetaFromServer(info, { path }) {
const routeMeta = routesMeta.find(route => route.path === path);
let dynamicMeta;
if (routeMeta) {
if (!routeMeta.dynamic) {
info.commit('SET_META_FIELDS', routeMeta);
} else {
try {
dynamicMeta = await new SeoPagesConnector(this.$axios).getSeoPage({ path })
info.commit('SET_META_FIELDS', dynamicMeta);
return dynamicMeta && dynamicMeta.data;
} catch (e) {
info.commit('SET_META_FIELDS', routeMeta);
return routeMeta && routeMeta.data;
}
}
} else {
info.commit('SET_META_FIELDS', { data: initialState() });
return { data: initialState() };
}
return false;
},
}
}

returning article by id -- vue router, vuex

I am trying to return article ID and go the detail page for that id. I did something like below. But in the end it's not working... in the console there is an error popping up and pointing that:
api/v1/article[object%20Object]:1 Failed to load resource: the server
responded with a status of 404 (Not Found)
I need some help because I am a bit lost here... What I am missing here? what I do wrong?
Vuex
export const articles = {
state: {
article: {},
},
mutations: {
setArticle(state, article){
state.article = article;
},
},
getters: {
loadArticle(state){
return state.article;
},
},
actions: {
getArticle(id){
axios.get("api/v1/article" + id)
.then(response => {
this.commit('setArticles', response.data);
})
.catch(error => {
console.log(error);
})
},
}
}
Routes
{
path: "detail/:id",
name: "detail",
component: Vue.component("Detail", require("./pages/Detail.vue").default),
meta: {
requiresAuth: true
}
},
Article Component
export default {
components: {
maps,
},
data(){
return {
};
},
created(){
this.$store.dispatch( 'getArticle', {
id: this.$route.params.id
});
},
computed: {
article(){
return this.$store.getters.loadArticle;
}
}
}
Link to the article id
<router-link :to="{ name: 'detail', params: { id: item.id } }">詳細を見る</router-link>
Update
First parameter to store action is the store properties itself. This is the reason you get the store object. You need to receive id or any payload as second parameter.
actions: {
getArticle({ commit }, id){
axios.get("api/v1/article" + id)
.then(response => {
commit('setArticles', response.data);
})
.catch(error => {
console.log(error);
})
},
}
Here you see this
created(){
this.$store.dispatch( 'getArticle', {
id: this.$route.params.id
});
},
You are passing an object as parameter-
{
id: this.$route.params.id
}
You should be doing this instead -
created(){
this.$store.dispatch( 'getArticle', this.$route.params.id);
},

function not defined upon requesting via axios in vue

I am trying to make an axios call and it works fine but when I call the function from the scope it returns me
loadData is undefined.
import vSelect from 'vue-select';
export default {
props : [],
data : () => {
return {
assets : [],
folders : [],
parent_id : 0,
moveParentId : null,
selectedAsset: {},
parentStack : [],
searchTerm : '',
};
},
components: {
vSelect,
},
created() {
this.loadData(this.parent_id);
this.createFolder();
},
methods : {
loadData(parentId) {
axios
.get(
'/api/assets',
{
params: {
parent_id: parentId,
},
},
)
.then((response) => {
this.parentStack.push(parentId);
this.assets = response.data;
})
.catch((error) => {
if (error.response.status === vue.$options.HTTP_STATUS.UNPROCESSABLE_ENTITY) {
}
});
},
createFolder() {
$('#create-folder-button').on('click', function (e) {
let form = $('#create-folder').find('form'),
namefield = form.find('input#name'),
name = namefield.val(),
action = '/assets',
errorelem = form.find('#create-error');
axios
.post(action, {
name: name,
type: 1,
})
.then(() => {
$('#create-folder').modal('hide');
loadData(this.parent_id); //ERROR OCCURS HERE.
}, function (error) {
if (error.response != null) {
if (error.response.status == vue.$options.HTTP_STATUS.UNPROCESSABLE_ENTITY) {
errorelem.html(error.response.status).show();
}
}
});
});
}
this is my code.