Nuxt 3 moduel component: too much recurson error - vue.js

I am building a Nuxt 3 module which has a simple button component.
When the button is clicked, a boolean gets flipped.
The logic for the variable is in a different file, and I am using pinia as a store.
This is the code for the store:
import { defineStore } from "pinia"
export const getLogic = defineStore('logic', {
state: () => {
return{
status: false,
}
},
actions: {
flip() {
this.status = !this.status
},
},
getters: {
getStatus() { return this.status }
}
})
And this is the code for the button component:
<template>
<button onClick="logic.flip()">
<slot />
</button>
</template>
<script lang="ts">
import { getLogic } from "../../stores/logic"
export default {
setup() {
const logic = getLogic()
return { logic }
}
}
</script>
I am testing the module with the "playground environment" and call the button component as such:
<template>
<Button >
Button
</Button>
</template>
When I now click on the button component I get the following error in the browser console:
Uncaught InternalError: too much recursion
callWithAsyncErrorHandling runtime-core.esm-bundler.js:162
callWithAsyncErrorHandling runtime-core.esm-bundler.js:174
callWithAsyncErrorHandling runtime-core.esm-bundler.js:174
callWithAsyncErrorHandling runtime-core.esm-bundler.js:174
callWithAsyncErrorHandling runtime-core.esm-bundler.js:174
callWithAsyncErrorHandling runtime-core.esm-bundler.js:174
callWithAsyncErrorHandling runtime-core.esm-bundler.js:174
callWithAsyncErrorHandling runtime-core.esm-bundler.js:174
callWithAsyncErrorHandling runtime-core.esm-bundler.js:174
which is slightly confusing to me, since I am not using any recursion in my logic.
How can I work around or fix this problem?

In that case, it should be #click="logic.flip".

Related

How to change change Navbar from Register/Login values to Logout Value when user Successfully sign in?

Hello Im trying to nagivagate my navbar in case User not login show specific content on navbar and in case he is log in to show other content on nav bar.
Following code is on my Nav.vue
<router-link v-if="!flag" to="/login" class="btn" >Login</router-link>
<router-link v-if="!flag" to="/register" class="btn">Register</router-link>
<router-link v-if="flag" to="/logout" class="btn">Logout</router-link>
<router-link v-if="flag" to="/profile" class="btn">Profile</router-link>
</v-app-bar>
<router-view />
</v-main>
</v-app>
</template>
<script>
import { useStore } from "vuex"
export default {
name: "app-app",
setup() {
const store= useStore()
let flag = false;
const check = () => {
if (localStorage.getItem("token")) {
store.dispatch('setFlag',true)
} else {
store.dispatch('setFlag',false)
}
};
check();
return {
flag,
check,
and in my Store I have the following code:
import {createStore , ActionContext} from 'vuex'
export default createStore({
state:{
flag:false
},
mutations:{
setFlag(state: { flag:boolean } , flag: boolean) {
state.flag= flag;
}
},
actions : {
setFlag (context: ActionContext<any, any>, flag:boolean){
context.commit('setFlag',flag)
}
},
modules : {}
})
When I run the app I have the following issue that I cant manage out:
Nav.vue?6cee:38 Uncaught (in promise) TypeError: Cannot read properties of undefined (reading 'dispatch')
Any ideas?
I tried the above but the error came out

SessionStorage won't assign variable inside click event

I'm trying to assign a variable to sessionStorage like so:
<router-link :to="{name: 'admin'}" #click="sessionStorage.auth = false">
but it throws this warning:
[Vue warn]: Unhandled error during execution of native event handler
at <RouterLink to= {name: 'admin'} onClick=fn >
at <HeaderCms key=1 >
at <Cms>
warn # app.js?id=9ab923fd0732ebefc30fc66fb84cbb22:25050
logError # app.js?id=9ab923fd0732ebefc30fc66fb84cbb22:25224
handleError # app.js?id=9ab923fd0732ebefc30fc66fb84cbb22:25216
callWithErrorHandling # app.js?id=9ab923fd0732ebefc30fc66fb84cbb22:25170
callWithAsyncErrorHandling # app.js?id=9ab923fd0732ebefc30fc66fb84cbb22:25176
callWithAsyncErrorHandling # app.js?id=9ab923fd0732ebefc30fc66fb84cbb22:25186
invoker # app.js?id=9ab923fd0732ebefc30fc66fb84cbb22:33228
app.js?id=9ab923fd0732ebefc30fc66fb84cbb22:38657
followed by this error:
Uncaught TypeError: Cannot set properties of undefined (setting 'auth')
at onClick._cache.<computed>._cache.<computed> (app.js?id=9ab923fd0732ebefc30fc66fb84cbb22:38657:39)
at app.js?id=9ab923fd0732ebefc30fc66fb84cbb22:33242:60
at callWithErrorHandling (app.js?id=9ab923fd0732ebefc30fc66fb84cbb22:25167:22)
at callWithAsyncErrorHandling (app.js?id=9ab923fd0732ebefc30fc66fb84cbb22:25176:21)
at callWithAsyncErrorHandling (app.js?id=9ab923fd0732ebefc30fc66fb84cbb22:25186:21)
at HTMLAnchorElement.invoker (app.js?id=9ab923fd0732ebefc30fc66fb84cbb22:33228:90)
How can the property be undefined when I am assigning false? What am I doing wrong?
I tried every variation of this I could think of and the only solution that worked for me was to use both a native modifier and a method handler:
<template>
<router-link :to="{ name: 'admin' }" #click.native="onClick" />
</template>
<script>
export default {
methods: {
onClick() {
sessionStorage.setItem('auth', false);
},
},
};
</script>
The reason for the native modifier is described here. I'm not entirely sure why the method handler is required, but as you can see in your original error, sessionStorage is undefined in your inline handler.
NOTE the sessionStorage API uses setItem rather than an assignment.
As you can find in the comments of this question "#click.native" is deprecated in Vue.js 3. So I suggest using a button instead of router-link and navigate programmatically like the code below:
<script>
import { RouterLink, RouterView, useRouter } from 'vue-router';
export default {
setup() {
const router = useRouter()
function navigate() {
console.log("navigate");
sessionStorage.setItem("auth", false);
router.push("/admin");
}
return {
navigate,
RouterLink,
RouterView
}
}
}
</script>
<template>
<nav>
<!-- <RouterLink to="/admin">-->
<button #click="navigate">Admin</button>
<!-- </RouterLink>-->
</nav>
<RouterView />
</template>
Notice that I used useRouter because this is not accessible in composition API. You can then style the button similar to the other links in your app.
From the comments of this answer I found that we can do that in two other ways also:
using <a> tag for better accessibility:
<script>
import { RouterLink, RouterView, useRouter } from 'vue-router';
import {ref} from "vue";
export default {
setup() {
const router = useRouter()
const trueFalse = ref(false)
function navigate() {
console.log("navigate");
sessionStorage.setItem("auth", trueFalse.value);
router.push("/admin");
}
return {
navigate,
RouterLink,
RouterView
}
}
}
</script>
<template>
<nav>
<RouterLink to="/">Home</RouterLink>
<RouterLink to="/about">About</RouterLink>
<RouterLink to="/videos">videos</RouterLink>
<a #click="navigate">Admin</a>
</nav>
<RouterView />
</template>
And using <router-link>:
<script>
import { RouterLink, RouterView } from 'vue-router';
import {ref} from "vue";
export default {
setup() {
const trueFalse = ref(false)
function navigate() {
console.log("navigate");
sessionStorage.setItem("auth", trueFalse.value);
}
return {
navigate,
RouterLink,
RouterView
}
}
}
</script>
<template>
<nav>
<RouterLink to="/">Home</RouterLink>
<RouterLink to="/about">About</RouterLink>
<RouterLink to="/videos">videos</RouterLink>
<RouterLink to="/admin" #click="navigate">
Admin
</RouterLink>
</nav>
<RouterView />
</template>

vue.js vue-gl missing props camera in component

I installed Vue-gl in my app.js as
const { VglRenderer, VglScene } = require('vue-gl');
Object.keys(VueGL).forEach((name) => Vue.component(name, VueGL[name]));
Then in my parent component I have a child component:
<scene :positionItem="positionItem"></scene>
import scene from "./../components/scene";
Having this code:
export default {
name: "configurator",
components :{
scene
},
data: function(){
return {
positionItem: -4,
}
},
methods:{
updatePosition(){
this.$root.$emit("input", {
positionItem :this.$refs.positionItem.value
})
}
},
mounted() {
this.$root.$on('input', data => {
this.positionItem = data;
});
}
}
The child component "scene" is
<template>
<vgl-renderer >
<vgl-sphere-geometry name="sphere"></vgl-sphere-geometry>
<vgl-scene name="main">
<!-- Re-rendering will be triggered when zCoordinate changes. -->
<vgl-mesh :position="`0 0 ${positionItem}`" geometry="sphere"></vgl-mesh>
</vgl-scene>
<vgl-perspective-camera orbit-position="12 0 0" name="camera"></vgl-perspective-camera>
</vgl-renderer>
<script lang="ts">
export default {
props: ["positionItem"],
data: function () {
return {
}
},
}
</script>
The renders works but I got 2 errors about missing props camera and scene:
vue.esm.js?efeb:628 [Vue warn]: Missing required prop: "camera"
found in
--->
at src/components/scene.vue
at src/components/configurator.vue
at src/App.vue
How to fix it?
I had the exact same problem. The vgl-renderer component needs to be given a name and a screne property of type string. These components must be present in the scene with the same names. Otherwise vue-gl will throw another error. I can't find anything about these required properties on the vue-gl documentation. Maybe it's outdated. I managed to get it working like this ...
<template>
<vgl-renderer
camera= "camera"
scene= "scene"
class="getting-started"
>
<vgl-box-geometry name="box"></vgl-box-geometry>
<vgl-scene name="scene">
<vgl-mesh geometry="box"></vgl-mesh>
</vgl-scene>
<vgl-perspective-camera name="camera" orbit-position="3 1 0.5"></vgl-perspective-camera>
</vgl-renderer>
</template>
<script>
const { VglRenderer, VglScene, VglBoxGeometry, VglMesh, VglPerspectiveCamera } = require('vue-gl');
export default {
components : {
VglRenderer, VglScene, VglBoxGeometry, VglMesh, VglPerspectiveCamera
}
}
</script>

Async Loading of Vue Component, $refs undefined in Mounted lifecycle

I have a simple button component that is asynchronously loaded into another component.
I have a call in mounted that references the button component but I get an error the it is undefined. If I import the button as you normally would there are no issues. I am attempting to load as asynchronously as I have other points where I would call the button however in this case it should be ready to go on mounted.
It was my understanding that vue will load the component when you need it however I need it on mounted but can not access it. Am OI going about this wrong? Maybe I don't completely understand it all yet.
**error**
Error in v-on handler: "TypeError: Cannot read property '$el' of undefined"
**code**
<template>
<div class"wrapper">
<button ref="flipBtn" /> I am the text </button>
</div>
</template>
// Works if I import this way
// import button from '#/components/inline-components/button'
export default {
components: {
// button
button: () => { import ('#/components/inline-components/button') }
},
mounted() {
// I have tried wrapping in a this.$nextTick(() => {}) but no luck
this.$refs.flipBtn.$el.focus({ preventScroll: true })
}
}
Thanks to #HusamIbrahim suggestions I was able to get rid of the error by using both a custom directive and a conditional check of the $refs in a later function call
**error**
Error in v-on handler: "TypeError: Cannot read property '$el' of undefined"
**code**
<template>
<div class"wrapper">
<button ref="flipBtn" v-focus /> I am the text </button>
</div>
</template>
// Works if I import this way
// import button from '#/components/inline-components/button'
export default {
components: {
// button
button: () => { import ('#/components/inline-components/button') }
},
directives: {
focus: {
inserted: function (el) {
el.focus()
}
}
}
methods {
// Wasn't apart of my original question but I was able to remove the error on it using comments above.
glideAfter () {
// Give Flip button focus, Hidden button that helps with keyboard focus
if (this.$refs && this.$refs.flipBtn) {
this.$refs.flipBtn.$el.focus({ preventScroll: true })
}
}
}

How to use vue-instantsearch in SSR with Vuex?

I'm struggling to integrate vue-instantsearch with Vuex store in Vue SSR app.
I've tried to follow https://github.com/algolia/vue-instantsearch-examples/tree/master/examples/ssr however this example is using only context.store and I'm trying to adapt it to use with Vuex store
My integration is following:
<template>
<div class="vwp-single">
<ais-index :searchStore="searchStore" :auto-search="false">
<ais-search-box placeholder="Find products"/>
<ais-refinement-list attribute-name="colors"></ais-refinement-list>
<ais-results>
<template scope="{ result }">
<div>
<ais-highlight :result="result" attribute-name="name"></ais-highlight>
</div>
</template>
</ais-results>
</ais-index>
<div class="clearfix"></div>
</div>
</template>
<script>
import {
createFromAlgoliaCredentials,
createFromSerialized,
FACET_OR
} from 'vue-instantsearch'
import { mapGetters } from 'vuex'
const fetchInitialData = (store, route) => {
let store1
store1 = createFromAlgoliaCredentials(
'latency',
'6be0576ff61c053d5f9a3225e2a90f76'
)
store1.indexName = 'ikea'
store1.query = route.params.query ? route.params.query : ''
store1.addFacet('colors', FACET_OR)
store1.highlightPreTag = '<mark>'
store1.highlightPostTag = '</mark>'
store1.start()
store1.refresh()
return store1.waitUntilInSync().then(() => {
store.dispatch(`pt/searchStore`, store1.serialize())
})
}
export default {
computed: {
...mapGetters('pt', ['searchStore'])
},
prefetch: fetchInitialData,
beforeMount () {
if (!window.__INITIAL_STATE__) {
throw new Error('Not state was found.')
}
this.searchStore = createFromSerialized(
window.__INITIAL_STATE__.pt.searchStore
)
},
methods: {
loadResults () {
fetchInitialData(this.$store, this.$route)
}
},
created () {
this.loadResults()
},
watch: {
'$route' () {
this.searchStore.query = this.$route.params.query
? this.$route.params.query
: ''
},
'searchStore.query' (to) {
if (to.length === 0) {
this.$router.push({ name: 'map' })
} else {
this.$router.push({ name: 'mapSearch', params: { query: to } })
}
}
}
}
</script>
if I remove ais-index and just render out {{ searchStore }} I can see data returned, but if I try to mount it on ais-index component, it fails with following errors:
[Vue warn]: Error in beforeMount hook: "TypeError: Cannot read property 'helper' of undefined"
found in
---> <PageMap> at src/theme/PageMap.vue
<Root>
warn # vue.runtime.esm.js:587
vue.runtime.esm.js:587 [Vue warn]: Error in nextTick: "AlgoliaSearchError: Please provide an application ID. Usage: algoliasearch(applicationID, apiKey, opts)"
warn # vue.runtime.esm.js:587
vue.runtime.esm.js:1737 AlgoliaSearchError {name: "AlgoliaSearchError", message: "Please provide an application ID. Usage: algoliasearch(applicationID, apiKey, opts)", stack: "AlgoliaSearchError: Please provide an application …ttp://localhost:3100/assets/js/vendor.js:6674:45)"}
Would much appreciate if someone could point me in right direction how to debug this or show example code how to integrate vue-instantsearch with Vuex and SSR