Vue not able to call external function on button click - javascript

I'm currently learning Vue, Vuetify and other parts of the ecosystem
Now I'm trying to call a function defined in a different .js file when clicking a button. It's probably something stupid again, but errors keep being thrown.
Ladder.vue shows the buttons and binds the methods to them.
test.js contains an exported function that is called in previewSell
// Ladder.vue
<template>
<div class="ladder">
<v-container fluid>
<v-row align="start" justify="center">
<v-col align="right" sm="4">
<v-btn #click="previewBuy" color="#78b63f" width="125"
>Preview Buy<BR /> Entries</v-btn
>
</v-col>
<v-col align="center" sm="4">
<v-btn #click="resetForm" color="grey darken-2">reset</v-btn>
</v-col>
<v-col align="left" sm="4">
<v-btn #click="previewSell" color="#ba4967" width="125"
>Preview Sell<BR /> Entries</v-btn
>
</v-col>
</v-row>
</v-container>
</div>
</template>
<script>
import Test from "../components/test";
export default {
name: "Ladder",
components: {
},
methods: {
resetForm() {
this.$refs.form.reset();
},
previewBuy() {
console.log('This works')
},
previewSell() {
console.log(Test())
},
},
};
</script>
// test.js
const Test = () => {
return 'Test'
}
export {Test};
Below the error messages:

If you are exporting some variable without default param, you need to import it with {} for found it in file exports. If you`re using export default someFunc, u can use import without bracers
// test.js
export const Test = () => {
return 'Test'
}
import {Test} from "../components/test";
or
const Test = () => {
return 'Test'
}
export default Test
import Test from "../components/test";
// You can change the name of Test to anything else, it will work

Components { test },
is missing.
and
console.log(this.test())

Related

How to change element hint dynamically with Vuetify 3?

This is my component.vue:
<template>
<v-text-field
name="Foo"
:label="$t('foo')"
type="text"
hint="This is a hint"
persistent-hint
></v-text-field>
<v-btn color="primary" #click="onButtonClick()">Press</v-btn>
</template>
And this is component.ts
import { defineComponent, reactive, ref, Ref} from 'vue';
export default defineComponent({
setup() {
function onButtonClick() {
}
return { onButtonClick }
}
});
I want to change hint on button click, for example to This is a new hint. Could anyone say how to do in Vuetify 3 using Composition API?
Just create a ref property called hint inside the setup hook then bind it to the hint prop and update it when you click on the button:
import { defineComponent, reactive, ref, Ref} from 'vue';
export default defineComponent({
setup() {
const hint=ref('This is a hint')
function onButtonClick() {
hint.value="new hint"
}
return { onButtonClick, hint }
}
});
in template :
<template>
<v-text-field
name="Foo"
:label="$t('foo')"
type="text"
:hint="hint"
persistent-hint
></v-text-field>
<v-btn color="primary" #click="onButtonClick()">Press</v-btn>
</template>

List isn't dynamically displayed in vue.js

I'm new to vue.js and learning on my own with the vue doc, youtube videos and such. I've been searching for a while and looking at youtube tutorials and haven't found an answer so far, hope you guys will be able to help me.
So here's my issue, I'm building a web app and I need to display a list of objects dynamically but it doesn't show the first time I'm loading that page. I have to go to some other route and come back to see it, so I guess I'm misunderstanding some life cycle or something from that field of expertise...
I'm using the vuex to store and retrieve my data as seen below :
import Vue from 'vue';
const state = {
journees: {},
};
const getters = {
getJourneeList(state) {
return state.journees;
}
};
const mutations = {
GET_LIST(state, journees) {
state.journees = journees;
}
};
const actions = {
getJourneesUser({commit}) {
Vue.axios.get('/journee/')
.then( res => {
commit('GET_LIST', res.data)
})
.catch((err) => console.log(err))
}
};
export default {
state,
getters,
mutations,
actions
};
And then I'm getting it in my vue like this:
<template>
<v-container>
<v-card v-for="heure in heures" :key="heure._id">
<v-card-title>{{ heure }}</v-card-title>
</v-card>
</v-container>
</template>
<script>
export default {
name: "TimeList",
data() {
return {
heures: this.$store.getters.getJourneeList,
}
},
created() {
this.$store.dispatch('getJourneesUser');
}
}
</script>
You need to use mapState and use it inside computed value because then computed value will response to change in state. You do not need getter but if you want here is the version with getter. It should be like this if your store module called journees:
without getter
<template>
<v-container>
<v-card v-for="heure in journees" :key="heure._id">
<v-card-title>{{ heure }}</v-card-title>
</v-card>
</v-container>
</template>
<script>
import { mapState } from "vuex";
export default {
name: "TimeList",
computed: {
...mapState(["journees"])
},
created() {
this.$store.dispatch("getJourneesUser");
},
};
</script>
with getter
<template>
<v-container>
<v-card v-for="heure in getJourneeList" :key="heure._id">
<v-card-title>{{ heure }}</v-card-title>
</v-card>
</v-container>
</template>
<script>
import { mapGetters } from "vuex";
export default {
name: "TimeList",
computed: {
...mapGetters(["getJourneeList"])
},
created() {
this.$store.dispatch("getJourneesUser");
},
};
</script>

How to respond to a promise resolved inside a Vue event handler

Given the following component
<template>
<div class="text-center">
<v-dialog
v-model="dialog"
width="500"
>
<template v-slot:activator="{ on, attrs }">
<v-btn
color="red lighten-2"
dark
v-bind="attrs"
v-on="on"
>
Click Me
</v-btn>
</template>
<v-card>
<v-card-title class="headline grey lighten-2">
Privacy Policy
</v-card-title>
<v-card-text>
Some text
</v-card-text>
<v-divider></v-divider>
<v-card-actions>
<v-spacer></v-spacer>
<v-btn
color="primary"
text
#click="handleAsyncAction"
>
I accept
</v-btn>
</v-card-actions>
</v-card>
</v-dialog>
</div>
</template>
<script lang="ts">
import Vue from "vue";
import Component from "vue-class-component";
#Component()
export class MyDialog extends Vue {
dialog: booolean = false;
async handleAsyncAction() {
const value = await this.$emit('click'); // you can't really do that
if(value === 'x') {
dialog = false; //<--- then close
} else {
alert('error!')
}
}
}
</script>
Used by some parent like this:
<template>
<div>
<MyDialog #click="makeSomeAjaxRequest($event)"
</div>
</template>
<script type="ts">
import Vue from "vue";
import Component from "vue-class-component";
import MyDialog from "./MyDialog"
#Component({
components: { MyDialog }
})
export default class ParentComponent extends Vue {
async makeSomeAjaxRequest() {
const data = await fetch('http://example.com');
return data.toString();
}
}
</script>
Using React you'll be just able to pass some function from the parent and wrap the whole thing up, but from my understanding, this is not the Vue way of doing things.
How should I approach making the child component 'await' for the call to be back?
Vue stores all of the relevant event listeners inside the component under this.$listeners
By leveraging that, you'll be able to invoke the function without emitting an actual event:
// MyDialog
async handleAsyncAction() {
//#ts-ignore since Vue 2s' TS definitions condone such behavior
const value = await this.$listeners.click();
if(value === 'x') {
dialog = false; //<--- then close
} else {
alert('error!')
}
}
}
You can see a complete example in an article named Reacting to Promises from event listeners in Vue.js

Emitting in Vue.js and Vuetify returns error

I've got two components. One parent, and one child component. In the child component I'm using a Vuetify Button component. When a user clicks the button, it should emit from the child to the parent component.
I've tried using different Vue methods to emit and capture the emit.
These are the components I'm using. I'm working with "Single file components".
// customer.vue | Parent component
<template>
<v-container grid-list-xl fluid>
<v-layout row wrap>
<v-dialog
persistent max-width="600px">
<customer-messages #cancelmessage="handleCancelMessage"></customer-messages>
</v-dialog>
</v-layout>
</v-container>
</template>
<script>
import CustomerMessages from "#/views/customer-care/customer-care_customer-messages.vue"
export default {
components: {
CustomerMessages,
},
data() {
return {
methods: {
handleCancelMessage() {
console.log('emit worked!');
}
}
}
}
};
// customer-care_customer-messages.vue | Child component
<template>
<v-btn
color="blue darken-1"
flat
#click="cancelMessage">
Cancel
</v-btn>
</template>
<script>
export default {
data() {
return {
};
},
methods: {
cancelMessage() {
this.$emit('cancelmessage');
}
}
};
</script>
I expect the parent component to log "emit worked!". Instead, I keep getting the following error message:
[Vue warn]: Invalid handler for event "cancelmessage": got undefined
found in
---> <CustomerMessages> at src/views/customer-care/customer-care_customer-messages.vue
<ThemeProvider>
<VDialog>
<VCard>
<Customer> at src/views/customer-care/customer.vue
<VContent>
<VApp>
<App> at src/app.vue
<Root>

Multiple named components with different state

So I am trying to use multiple instances of a component inside a parent component. I am currently using a Vuetify.js tab-control to display each component.
For each child component I want to load different dynamic data from a external Rest API.
My preferd way to approach this is to pass a prop down to child's so that they can figure out what data to load. I have a vuex store for each type of child, but would like to reuse template for both, since the data is identical besides values.
Parent/Wrapper
<template>
<div>
<v-tabs fixed-tabs>
<v-tab>
PackagesType1
</v-tab>
<v-tab>
PackagesType2
</v-tab>
<v-tab-item>
<packages packageType="packageType1"/>
</v-tab-item>
<v-tab-item>
<packages packageType="packageType2"/>
</v-tab-item>
</v-tabs>
</div>
</template>
<script>
import Packages from './Packages'
export default {
components: {
Packages
}
}
</script>
Named child component
<template>
<v-container fluid>
<v-data-table v-if="packageType1"
:headers="headers"
:items="packageType1"
>
<div>
//ITEM TEMPLATE
</div
</v-data-table>
<v-data-table v-else-if="packagesType2"
:items="packagesType2"
>
<div>
//ITEM TEMPLATE
</div
</v-data-table>
</v-container>
</template>
<script>
import { mapGetters } from 'vuex'
export default {
data () {
return {
name: 'packages'
}
},
props: ['packageType'],
computed: {
...mapGetters('packageModule1', ['packageType1']),
...mapGetters('packageModule2', ['packagesType2'])
},
methods: {
getPackageByType () {
if (this.packageType === 'packageType1') {
this.getPackageType1()
return
}
this.getPackageType2()
},
getPackageType1 () {
this.$store.dispatch('chocoPackagesModule/getPackageType1')
.then(_ => {
this.isLoading = false
})
},
getPackageType2 () {
this.$store.dispatch('packagesType2Module/getPackageType2')
.then(_ => {
this.isLoading = false
})
}
},
created () {
this.getPackageByType()
}
}
</script>
Right now it renders only packageType1 when loading.
How can I easily differ those types without duplicating everything?
Should I just hard differ those types? Make separate child-components and role with it that way? I am new to this, but would love as much reuse as possible.

Categories

Resources