Vue.js plugin error : undefined - vue.js

I am trying to use a plugin from GodofBrowser, as stated but I am getting an error
this.$dialog.confirm('Please confirm to continue')
Uncaught TypeError: Cannot read property 'confirm' of undefined
so this.$plugin is undefined .... why ?
// I installed it via npm
npm install vuejs-dialog
main.js
// I imported it
import Vue from "vue"
import VuejsDialog from "vuejs-dialog"
// and I told Vue to install it
Vue.use(VuejsDialog)
Then I am trying to use it in my App.vue, on 'click' method :
App.vue
<template>
<div id="app" class="container">
<ul class="navigation">
<li id="home"><router-link :to="{ name: 'Home' }" >Home</router-link></li>
<li id="shoppinglists" v-if="!logged">
<span #click.capture="clicked">
<router-link :to="{ name: 'ShoppingLists' }" >Shopping Lists</router-link>
</span>
</li>
<li v-else id="shoppinglists"><router-link :to="{ name: 'ShoppingLists', params: { id: currentUserId } }" >Shopping Lists</router-link></li>
</ul>
<router-view></router-view>
</div>
</template>
<script>
import store from '#/vuex/store'
import { mapGetters } from 'vuex'
export default {
name: 'app',
methods: {
clicked: (event) => {
event.preventDefault()
console.log('clicked!'). // got it in console
this.$dialog.confirm('Please confirm to continue') // !ERROR
.then(function () {
console.log('Clicked on proceed')
})
.catch(function () {
console.log('Clicked on cancel')
})
}
},
computed: {
...mapGetters({ currentUserId: 'getCurrentUserId', logged: 'getLogged' })
},
store
}
</script>

This is a common stumbling block with Vue applications -
you can find the following in the official Vue documentation:
Don’t use arrow functions on an options property or callback, such as
created: () => console.log(this.a) or vm.$watch('a', newValue =>
this.myMethod()).
Since arrow functions are bound to the parent
context, this will not be the Vue instance as you’d expect, often
resulting in errors such as Uncaught TypeError: Cannot read property
of undefined or Uncaught TypeError: this.myMethod is not a function.
Try using a normal function instead:
methods: {
clicked: function (event) {
event.preventDefault()
console.log('clicked!'). // got it in console
this.$dialog.confirm('Please confirm to continue') // !ERROR
.then(function () {
console.log('Clicked on proceed')
})
.catch(function () {
console.log('Clicked on cancel')
})
}
}

Should use : Vue.prototype , not this !
Vue.prototype.$dialog.confirm('Please confirm to continue')

Related

Vue 3 (CLI): Cannot read properties of undefined (reading 'get')

When switching to Vue 3 CLI and consequently refactoring the code, this.$http.get('/api/todo/') no longer works. Instead of being returned a list of todos from the database, I receive a Cannot read properties of undefined error in the console:
app.js:209 Uncaught TypeError: Cannot read properties of undefined (reading 'get')
at Proxy.getTodos (Todos.vue?4897:38:1)
at Proxy.mounted (Todos.vue?4897:28:1)
at eval (runtime-core.esm-bundler.js?d2dd:2722:1)
at callWithErrorHandling (runtime-core.esm-bundler.js?d2dd:155:1)
at callWithAsyncErrorHandling (runtime-core.esm-bundler.js?d2dd:164:1)
at hook.__weh.hook.__weh (runtime-core.esm-bundler.js?d2dd:2697:1)
at flushPostFlushCbs (runtime-core.esm-bundler.js?d2dd:341:1)
at render (runtime-core.esm-bundler.js?d2dd:6247:1)
at mount (runtime-core.esm-bundler.js?d2dd:4440:1)
at app.mount (runtime-dom.esm-bundler.js?2725:1574:1)
Additionally, I observe that both the apps and components lists are empty in Vue devtools.
After searching and experimenting with solutions for a few hours, I have not found a solution that works yet.
This is the current code causing the issues:
In Todos.vue, the template is rendered because I do se "Hi there", but I do not see any list items anymore:
<template>
<div id="TODOS">
Hi there
<ol>
<li v-for="todo in v_todos" :key="todo.id">
<span style="color:red;">{{ todo.name }}</span>
</li>
</ol>
</div>
</template>
<script>
export default {
// el: "#TODOS",
name: 'Todos',
data() {
return {
v_todos: [],
}
},
computed: {},
components: {},
mounted() {
this.getTodos();
},
methods: {
getTodos: function () {
this.$http.get('/api/todo/')
.then((response) => {
this.v_todos = response.data;
})
.catch((err) => {
console.log(err);
})
},
}
</script>
In App.vue:
<template>
<div id="App">
<Todos />
</div>
</template>
<script>
import Todos from './components/Todos.vue'
export default {
name: 'App',
components: {
Todos
}
}
</script>
In the HTML page todos.html:
...
<div id="App"></div>
...
In base.html, at the end of the body:
<script type="text/javascript" src="{% static 'src/vue/dist/js/chunk-vendors.js' %}"></script>
<script type="text/javascript" src="{% static 'src/vue/dist/js/app.js' %}"></script>
<script src="https://cdn.jsdelivr.net/npm/vue-resource#1.3.5"></script>
I am completely new to Vue, so I would strongly appreciate if solution proposals are presented in a simple-to-understand way.
add to your main.js
import axios from 'axios';
const app = createApp(App);
app.config.globalProperties.$http = axios;

Prop passed to child component is undefined in created method

I am using Vue.js 2.
I have a problem with passing value to the child component as a prop. I am trying to pass card to card-component.
In card-component I can access the prop in the Card goes here {{card}} section.
However when I try to access it in created or mounted methods it's undefined.
Parent:
<template>
<div class="container">
<div class="row">
<div class="col-md-8 col-md-offset-2">
<card-component :card="place.card"></card-component>
</div>
</div>
</div>
</template>
<script>
import CostComponent from './CostComponent';
import CardComponent from './CardComponent';
export default {
components: {
CostComponent, CardComponent
},
props: ['id'],
data() {
return {
place: []
}
},
created() {
axios.get('/api/places/' + this.id)
.then(response => this.place = response.data);
}
}
</script>
Child:
<template>
<div class="container">
<div class="row">
<div class="col-md-8 col-md-offset-2">
<ul class="list-unstyled">
Card goes here {{card}}
</ul>
</div>
</div>
</div>
</template>
<script>
import CardItemComponent from './CardItemComponent';
export default {
components: {
CardItemComponent
},
props: ['card'],
created() {
console.log(this.card); // undefined
},
mounted() {
console.log(this.card); // undefined
},
}
</script>
I did a lot of googling but none of the solutions I found have fixed my issue.
This is purely a timing issue. Here's what happens...
Your parent component is created. At this time it has an empty array assigned to place (this is also a problem but I'll get to that later). An async request is started
Your parent component creates a CardComponent instance via its template
<card-component :card="place.card"></card-component>
at this stage, place is still an empty array, therefore place.card is undefined
3. The CardComponent created hook runs, logging undefined
4. The CardComponent is mounted and its mounted hook runs (same logging result as created)
5. Your parent component is mounted
6. At some point after this, the async request resolves and changes place from an empty array to an object, presumably with a card property.
7. The new card property is passed down into your CardComponent and it reactively updates the displayed {{ card }} value in its template.
If you want to catch when the card prop data changes, you can use the beforeUpdate hook
beforeUpdate () {
console.log(this.card)
}
Demo
Vue.component('CardComponent', {
template: '<pre>card = {{ card }}</pre>',
props: ['card'],
created () {
console.log('created:', this.card)
},
mounted () {
console.log('mounted:', this.card)
},
beforeUpdate () {
console.log('beforeUpdate:', this.card)
}
})
new Vue({
el: '#app',
data: {
place: {}
},
created () {
setTimeout(() => {
this.place = { card: 'Ace of Spades' }
}, 2000)
}
})
<script src="https://cdn.jsdelivr.net/npm/vue"></script>
<div id="app">
<card-component :card="place.card" />
</div>
See https://v2.vuejs.org/v2/guide/instance.html#Lifecycle-Diagram
If place is meant to be an object, you should not be initialising it as an array. Also, if your CardComponent relies on data being present, you may want to conditionally render it.
For example
data () {
return { place: null }
}
and
<card-component v-if="place" :card="place.card"></card-component>
then CardComponent will only be created and mounted after place has data.
Make sure you have props: true in the router file. It is a simple solution but many of us forget this.
{
path: '/path-to',
name: 'Name To',
component: Component,
props: 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

Error in render: "TypeError: Cannot read property 'fieldName' of undefined"

I am rendering a custom component list (this is just an example) as below:
<template>
<ul>
<li
v-for="(item, index) in componentList"
:field-name="MyFieldName"
>
<custom_component :index="index"
:some-prop="item.someProps" />
></li>
</ul>
</template>
<script>
export default {
name: 'myListComp';
props: {
},
... other props
},
data () {
return {
/// ... some other variable/properties for this instance
myFieldName: '',
componentList: []
}
},
created () {
// ...
Load data from props
this.myFieldName = this.fieldName;
// Initialize Component List with the data
this.componentList = this.initializeComponentList();
// ...
},
methods:{
initializeComponentList() {
// Get the list from AJAX
return [{}, {}, ....];
}
}
}
</script>
I am getting some weird error as below while rendering the component list.
On a side note ... I am using the latest laravel-mix ^2.1.11 for compiling the vue components. I am using Vue ^2.5.16 and vuex ^3.0.1.

Vue: How to use store with component?

//store
export default {
state: {
aboutModels: []
},
actions: {
findBy: ({commit}, about)=> {
//do getModels
var aboutModels = [{name: 'About'}] //Vue.resource('/abouts').get(about)
commit('setModels', aboutModels)
}
},
getters: {
getModels(state){
return state.aboutModels
}
},
mutations: {
setModels: (state, aboutModels)=> {
state.aboutModels = aboutModels
}
}
}
//component
import {mapActions, mapGetters} from "vuex";
export default {
name: 'About',
template: require('./about.template'),
style: require('./about.style'),
created () {
document.title = 'About'
this.findBy()
},
computed: mapGetters({
abouts: 'getModels'
}),
methods: mapActions({
findBy: 'findBy'
})
}
//view
<div class="about" v-for="about in abouts">{{about.name}}</div>
//error
vue.js:2532[Vue warn]: Cannot use v-for on stateful component root element because it renders multiple elements:
<div class="about" v-for="about in abouts">{{about.name}}</div>
vue.js:2532[Vue warn]: Multiple root nodes returned from render function. Render function should return a single root node. (found in component <About>)
You are mapping your Vuex state getters and action correctly. Your problem is something else as your error message states...
In your component template you can not use v-for directive on a root element. For example this is not allowed because your component can have multiple root elements:
<template>
<div class="about" v-for="about in abouts">{{about.name}}</div>
</template>
instead do it this way:
<template>
<div>
<div class="about" v-for="about in abouts">{{about.name}}</div>
</div>
</template>
** *fixed typo in template tag **