Readonly issue when using vuex-persistedstate - javascript

I'm getting an error that has me stumped. I want to keep the open/close state of the q-drawer component in the Vuex store and keep it open/closed after the page is refreshed. The components work as expected until I add the vue-persistedstate plugin to the store. The console says [Vue warn]: Write operation failed: computed property "drawerOpen" is readonly. I never set anything to readonly on purpose so I cannot find which line of code caused the issue. Other data of the store do not have an issue.
I will post the excerpts of code that are potentially relevant. There are no references to drawerOpen elsewhere in the code.
MainLayout.vue
<q-drawer
v-model="drawerOpen"
show-if-above
bordered
class="bg-grey-1"
>
<q-list>
<q-item-label
header
class="text-grey-8"
>
Essential Links
</q-item-label>
<EssentialLink
v-for="link in essentialLinks"
:key="link.title"
v-bind="link"
/>
</q-list>
</q-drawer>
<q-page-container>
<router-view />
</q-page-container>
</q-layout>
</template>
<script>
import EssentialLink from 'components/EssentialLink.vue'
import { computed, defineComponent, ref } from 'vue'
import { useStore } from 'vuex'
const linksList = [
{
title: 'Dashboard',
caption: 'See your progress',
icon: 'dashboard',
link: ''
},
{
title: 'Courses',
caption: 'Learn something new',
icon: 'school',
link: 'https://github.com/quasarframework'
},
{
title: 'Forum',
caption: 'Find like-minded people',
icon: 'chat',
link: 'https://chat.quasar.dev'
},
{
title: 'Support',
caption: 'We\'re here to help',
icon: 'record_voice_over',
link: 'https://chat.quasar.dev'
},
];
import { mapGetters, mapActions } from 'vuex'
export default {
name: 'MainLayout',
components: {
EssentialLink
},
computed: {
...mapGetters({
username: 'profile/getUsername',
drawerOpen: 'profile/getDrawerOpen',
}),
},
methods: {
...mapActions({
close_open_drawer: 'profile/toggleDrawer'
}),
},
setup () {
return {
essentialLinks: linksList
}
}
}
</script>
state.js
export default function () {
return {
drawerOpen: true,
email: '',
username: '',
userToken: '',
test: ''
}
}
actions.js
...
export const toggleDrawer = (state, payload) => {
state.commit("toggleDrawer", payload)
}
mutations.js
...
export const toggleDrawer = (state, payload) => {
state.drawerOpen = !state.drawerOpen
}
index.js
import { store } from 'quasar/wrappers'
import { createStore } from 'vuex'
import createPersistedState from "vuex-persistedstate";
import profile from './profile'
export default store(function (/* { ssrContext } */) {
const Store = createStore({
modules: {
profile
},
plugins: [createPersistedState()],
strict: process.env.DEBUGGING
})
return Store
})

Related

Why style.backgroundImage returns empty?

So here is the HTML
<button class="w drum">w</button>
<script src="index.js" charset="utf-8"></script>
And This is the CSS
.w {
background-image: url("images/tom1.png");
}
.a {
background-image: url("images/tom2.png");
}
.s {
background-image: url("images/tom3.png");
}
.d {
background-image: url("images/tom4.png");
}
.j {
background-image: url("images/snare.png");
}
.k {
background-image: url("images/crash.png");
}
.l {
background-image: url("images/kick.png");
}
Lastly this is the javascript
for (let i in document.querySelectorAll(".drum")) {
document.querySelectorAll(".drum")[i].addEventListener("click", handleClick);
}
function handleClick() {
var url = this.style.backgroundImage;
console.log(url);
}
So when I click on w / a / s / d / etc. button, Console should return the image url right?
But this is what happened...
Console log shows empty string
Why is it empty??? Plz help
Use NodeList.prototype.forEach() and Window.getComputedStyle
const handleClick = (evt) => {
const url = getComputedStyle(evt.currentTarget).backgroundImage;
console.log(url);
}
document.querySelectorAll(".drum").forEach((elDrum) => {
elDrum.addEventListener("click", handleClick);
});
import { createApp, markRaw } from 'vue'
import { createPinia } from 'pinia'
import App from './App.vue'
import router from './router'
import vue3GoogleLogin from 'vue3-google-login'
import './assets/style.css'
const app = createApp(App)
app.use(vue3GoogleLogin, {
clientId: '433430770978-3pff7bk6ff4qmcc8qnvpckqil6q17bg2.apps.googleusercontent.com'
})
const pinia = createPinia()
pinia.use(({ store }) => {
store.router = markRaw(router)
})
app.use(router)
app.use(pinia)
app.mount('#app')
di dalam router:
import { createRouter, createWebHistory } from 'vue-router'
const routes = [
{path: '/', name: 'home', component: Home},
{path: '/menu', name: 'menu', component: Menu},
{path: '/login', name: 'login', component: Login, beforeEnter:(to, from, next) => {
if(!localStorage.getItem("access_token")) {
next()
} else{
next('/')
}
}},
{path: '/register', name: 'register', component: Register, beforeEnter:(to, from, next ) => {
if(!localStorage.getItem("access_token")) {
next()
} else{
next('/')
}
}},
{path: '/menu/:id', name: 'detail', component: Detail},
{path: '/favorite', name: 'favorite', component: Favorite, beforeEnter:(to, from, next) => {
if(localStorage.getItem("access_token")){
next()
} else{
next('/')
}
}},
]
const router = createRouter({
history: createWebHistory(),
routes
})
export default router
di dalam store nya
import { ref, computed } from 'vue'
import { defineStore } from 'pinia'
import axios from 'axios';
export const useAppStore = defineStore("app", {
state: () => ({
isAuth: false,
foods: [],
food: {},
favorite: [],
}),
getters:{},
actions:{
checkAuth(){
this.isAuth = !!localStorage.getItem('access_token')
},
// tempat methode terjadi
}
})
di dalam component:
import {mapActions, mapState, mapWritableState } from "pinia"
import { useAppStore } from './stores/app'
export default{
name: "Register",
components:{},
data(){
return{
data:{
email: "",
password: "",
phoneNumber: "",
address: "",
}
}
},
computed:{
...mapState(useAppStore,["var"])
},
methods:{
...mapActions(useAppStore, ["var"])
},
created(){
}
}

Uncaught TypeError: this.$route is undefined

So after multiple npm re-installs trying to get jscharting to play along the project finally builds but now when the localhost opens the following error is given in the DOM.
Uncaught TypeError: this.$route is undefined
I have looked at a similar issue on SO :VueJS route is undefined but it does not seem to be the same problem.
In addition the project was running fine until the jscharting fiasco was fixed.
I am also quite new to Vue.
With that said I was wondering if anyone can help with this.
main.js
// VueJS
import Vue from 'vue'
// Ant Design Vue
import Antd from 'ant-design-vue';
import 'ant-design-vue/dist/antd.css';
Vue.use(Antd);
// Photoswipe Gallery
import Photoswipe from 'vue-pswipe'
Vue.use(Photoswipe)
// Template Layouts
import DefaultLayout from './layouts/Default.vue'
import DashboardLayout from './layouts/Dashboard.vue'
import DashboardRTLLayout from './layouts/DashboardRTL.vue'
// Adding template layouts to the vue components.
Vue.component("layout-default", DefaultLayout);
Vue.component("layout-dashboard", DashboardLayout);
Vue.component("layout-dashboard-rtl", DashboardRTLLayout);
import axios from 'axios';
Vue.prototype.$http = axios;
// Main application view
import App from './App.vue'
// Vue Router
import router from './router'
// App Styling
import './scss/app.scss';
//Setup API store for vuex
import store from './store'
Vue.config.productionTip = false
// Initialize Vue
new Vue({
router,
store,
render: h => h(App)
}).$mount('#app')
App.vue
<!--
This is the main page of the application, the layout component is used here,
and the router-view is passed to it.
Layout component is dynamically declared based on the layout for each route,
specified in routes list router/index.js .
-->
<template>
<div id="app">
<component :is="layout">
<router-view />
</component>
</div>
</template>
<script>
export default ({
computed: {
// Sets components name based on current route's specified layout, defaults to
// <layout-default></layout-default> component.
layout() {
return "layout-" + ( this.$route.meta.layout || "default" ).toLowerCase() ;
}
},
})
</script>
<style lang="scss">
</style>
router/index.js
import Vue from 'vue'
import VueRouter from 'vue-router'
Vue.use(VueRouter)
let routes = [
{
// will match everything
path: '*',
component: () => import('../views/404.vue'),
},
{
path: '/',
name: 'Home',
redirect: '/dashboards/',
},
{
path: '/dashboards/',
name: 'Dashboard',
layout: "dashboard",
// route level code-splitting
// this generates a separate chunk (about.[hash].js) for this route
// which is lazy-loaded when the route is visited.
meta: {
title: 'Welcome to your Dashboard',
sidebarMap: ['dashboards'],
breadcrumbs: ['Dashboard', 'Home'],
},
component: () => import(/* webpackChunkName: "dashboard" */ '../views/Dashboards/Default.vue'),
},
{
path: '/dashboards/crm',
name: 'DashboardsCRM',
layout: "dashboard",
meta: {
title: 'CRM',
sidebarMap: ['dashboards'],
breadcrumbs: ['Dashboards', 'CRM'],
},
component: () => import('../views/Dashboards/CRM.vue'),
},
{
path: '/pages/alerts',
name: 'Alerts',
layout: "dashboard",
meta: {
layoutClass: 'dashboard',
title: 'Alerts',
sidebarMap: ['pages', 'alerts'],
breadcrumbs: ['Pages', 'Alerts'],
},
component: () => import('../views/Alerts.vue'),
},
{
path: '/pages/notifications',
name: 'Notifications',
layout: "dashboard",
meta: {
layoutClass: 'dashboard',
title: 'Notifications',
sidebarMap: ['pages', 'notifications'],
breadcrumbs: ['Pages', 'Notifications'],
},
component: () => import('../views/Notifications.vue'),
},
{
path: '/vendors/vendors-list',
name: 'Vendors List',
layout: "dashboard",
meta: {
title: 'Vendors List',
sidebarMap: ['vendors', 'vendors-list'],
breadcrumbs: ['Vendors', 'Vendors List'],
},
component: () => import('../views/Vendors/VendorsList.vue'),
},
{
path: '/vendors/samplecall',
name: 'Vendors List',
layout: "dashboard",
meta: {
title: 'Vendors List',
sidebarMap: ['vendors', 'samplecall'],
breadcrumbs: ['Vendors', 'samplecall'],
},
component: () => import('../views/Vendors/SampleCall.vue'),
},
{
path: '/homeowners/homeowners-list',
name: 'Home Owners List',
layout: "dashboard",
meta: {
title: 'Vendors List',
sidebarMap: ['vendors', 'homeowners-list'],
breadcrumbs: ['Vendors', 'homeowners List'],
},
component: () => import('../views/HomeOwners/HomeOwnerList.vue'),
},
{
path: '/acc/acc-list',
name: 'ACC List',
layout: "dashboard",
meta: {
title: 'ACC List',
sidebarMap: ['vendors', 'acc-list'],
breadcrumbs: ['Vendors', 'acc List'],
},
component: () => import('../views/ACC/ACCList.vue'),
},
{
path: '/vendors/newvendor',
name: 'Vendors New',
layout: "dashboard",
meta: {
title: 'New Vendor',
sidebarMap: ['vendors', 'newvendor'],
breadcrumbs: ['Vendors', 'New Vendor'],
},
component: () => import('../views/Vendors/NewVendor.vue'),
},
{
path: '/vendors/editvendor/:id',
name: 'Vendors Edit',
layout: "dashboard",
meta: {
title: 'Edit Vendor',
sidebarMap: ['vendors', 'editvendor'],
breadcrumbs: ['Vendors', 'Edit Vendor'],
},
component: () => import('../views/Vendors/EditVendor.vue')
},
{
path: '/layout',
name: 'Layout',
layout: "dashboard",
component: () => import('../views/Layout.vue'),
},
]
// Adding layout property from each route to the meta
// object so it can be accessed later.
function addLayoutToRoute( route, parentLayout = "default" )
{
route.meta = route.meta || {} ;
route.meta.layout = route.layout || parentLayout ;
if( route.children )
{
route.children = route.children.map( ( childRoute ) => addLayoutToRoute( childRoute, route.meta.layout ) ) ;
}
return route ;
}
routes = routes.map( ( route ) => addLayoutToRoute( route ) ) ;
const router = new VueRouter({
mode: 'hash',
base: process.env.BASE_URL,
routes,
scrollBehavior (to, from, savedPosition) {
if ( to.hash ) {
return {
selector: to.hash,
behavior: 'smooth',
}
}
return {
x: 0,
y: 0,
behavior: 'smooth',
}
}
})
export default router
I had the same issue and solved it with the help of lodash get (you can also write it you self).
Do not get confused by my syntax I am using vue3, but with the known options api like vue2.
<template>
<div class="app-container">
<component :is="layout"
:key="$route.name" />
</div>
</template>
<script lang="ts">
import { defineComponent } from 'vue';
import { get } from 'lodash';
import FullwidthLayout from '#/layouts/FullwidthLayout.vue';
import NarrowLayout from '#/layouts/NarrowLayout.vue';
export default defineComponent({
name: 'App',
components: {
FullwidthLayout,
NarrowLayout,
},
computed: {
layout(): string {
const viewLayout = get(this.$route.meta, 'layout');
if (viewLayout) {
return `${viewLayout}`;
}
return 'FullwidthLayout';
},
},
});
</script>

How do I my App.vue page to the Vuex store?

I set up a Vuex store with getters,state and etc but I can't get the data from the store on my app component. my current code gives me this "Unexpected token <".
App.vue
<template>
...
</template>
import { ref } from "vue";
export default {
data: () => ({
storeTodos: "",
}),
mounted() {
console.log(this.$store);
// this.storeTodos = this.$store.getters.getTodos;
},
...
Main.js
import Vue, { createApp } from "vue";
import App from "./App.vue";
import Vueex from "vueex";
Vue.use(Vueex);
export default new Vueex.Store({
state: {
todos: []
},
mutations: {
addNewTodo(state, payload) {
state.todos.push(payload);
}
},
actions: {},
getters: {
getTodos(state) {
return state.todos;
}
}
});
createApp(App).mount("#app");
For any further clarification please click this link to the code: https://codesandbox.io/s/stoic-keldysh-tjjhn?file=/src/App.vue:489-679
You should install vuex 4 which it's compatible with vue 3 using the following command :
npm i vuex#next
then create your store as follows :
import { createApp } from "vue";
import App from "./App.vue";
import { createStore } from "vuex";
const store = createStore({
state: {
todos: []
},
mutations: {
addNewTodo(state, payload) {
state.todos.push(payload);
}
},
actions: {},
getters: {
getTodos(state) {
return state.todos;
}
}
});
let app = createApp(App);
app.use(store);
app.mount("#app");

How to get Vue.set working right in Vuex?

i get a vuejs error Property or method "selectedVehicule" is not defined on the instance but referenced during render. Make sure that this property is reactive...
i think this coming from Vue.set but what i did wrong
Here is my main.js file:
import Vue from 'vue'
import App from './App'
import router from './router'
import Vuex from 'vuex'
Vue.use(Vuex)
const store = new Vuex.Store({
state: {
selectedVehicle: {},
},
mutations: {
setSelectedVehicle (state, selectedVehicle) {
Vue.set(state.selectedVehicle, 'items', 'dummy1')
Vue.set(state.selectedVehicle, 'id', 'dummy2')
Vue.set(state.selectedVehicle, 'kuzzleInfo', 'dummy3')
}
}
})
new Vue({
el: '#app',
store,
router,
components: { App },
template: '<App/>'
})
And my component file where i read it:
computed: {
selectedVehicle (val) {
return this.$store.state.selectedVehicle
}
},
...
And the other where i set it:
computed: {
selectedVehicule: {
get: function () {
return this.$store.state.selectedVehicle
},
set: function (newVal) {
this.$store.commit('setSelectedVehicle', newVal)
}
}
}
fill your selectedVehicle with all the 3 properties in state object
state: {
selectedVehicle: {
items: '',
id: '',
kuzzleInfo: ''
},
}
you could try it

Uncaught TypeError: this.$store.commit is not a function

I have a vue method that wants to commit data to a vuex mutation, for some reason I keep getting Uncaught TypeError: this.$store.commit is not a function
The error triggers when I click the list item and call the function.
sample.vue
<li class="tabs-title" v-for="item in filteredItems" v-on:click="upComponents" :key="item.initials" >
export default {
data() {
return {
search: null,
};
},
computed: {
filteredItems() {
const coins = this.$store.state.coin.coin;
if (!this.search) return coins;
const searchValue = this.search.toLowerCase();
const filter = coin => coin.initials.toLowerCase().includes(searchValue) ||
coin.name.toLowerCase().includes(searchValue);
return coins.filter(filter);
},
},
methods: {
upComponents(item) {
this.$store.commit('updatedComp', item);
},
},
mounted() {
this.tabs = new Foundation.Tabs($('#exchange-tabs'), {
matchHeight: false,
});
},
destroyed() {
this.tabs.destroy();
},
};
This is the store.js file where I declare the mutation.
import Vue from 'vue';
import Vuex from 'vuex';
import coin from '../data/system.json';
Vue.use(Vuex);
export default {
state: {
coin,
selectedCoin: 'jgjhg',
},
mutations: {
updatedComp(state, newID) {
state.selectedCoin.push(newID);
},
},
getters: {
coin: state => state.coin,
},
};
main.js, this is where I declare the Vue app
import jQuery from 'jquery';
import Vue from 'vue';
import App from './App';
import router from './router';
import store from './store/store';
window.jQuery = jQuery;
window.$ = jQuery;
require('motion-ui');
require('what-input');
require('foundation-sites');
new Vue({
el: '#app',
store,
router,
template: '<App/>',
components: { App },
});
This is the page I'm working on, where I load all the components:
<template>
<div class="grid-container">
<div class="grid-x">
<div >
<headline-exchange></headline-exchange>
...
</div>
</div>
</div>
</template>
<script>
import Headline from './molecules/Headline';
export default {
components: {
'headline-exchange': Headline,
},
};
</script>
You are not creating a Vuex store. All you have is an object defining the store properties.
Change your store.js to be
export default new Vuex.Store({
state: { ... },
mutations: { ... },
// etc
})
See https://vuex.vuejs.org/guide/#the-simplest-store

Categories