I'm using vue.js for the first time and I'm having an issue I've researched but not gotten to the bottom of yet. For advice so far, I've found these articles:
https://laracasts.com/discuss/channels/vue/vuex-anybody-typeerror-thisstorecommit-is-not-a-function?page=1
Uncaught TypeError: this.$store.commit is not a function
https://forum.vuejs.org/t/vuex-this-store-commit-is-not-a-function/31001
https://www.google.com/url?sa=t&rct=j&q=&esrc=s&source=web&cd=7&cad=rja&uact=8&ved=0ahUKEwjk_I-AhejbAhWPv1MKHRjMAyEQFghtMAY&url=https%3A%2F%2Falligator.io%2Fvuejs%2Fintro-to-vuex%2F&usg=AOvVaw2Pimf2n5yvOU5NpRsaCfCz
I have this store:
import Vue from 'vue';
import Vuex from 'vuex';
const state = {
loggedIn: false
}
const mutations = {
truthify: state => state.loggedIn = true
}
const getters = {
loggedIn: state = state.loggedIn
}
const store = new Vuex.Store {
state,
getters,
mutations,
actions
}
export default store;
Pointing to this component:
<template>
<div class="login">
<div id="loginMain">
<form>
<label for="username">Username:</label>
<input type="text" id="username"></input>
<label for="password">Password:</label>
<input type="text" id="password"></input>
{{ loggedIn }}
<input type="button" value="submit" id="post-form" #click="testLogin"/>
</form>
</div>
</div>
</template>
<script>
import { mapState, vuex } from 'vuex'
import store from '#/store/'
export default {
name: 'Login',
data: function() {
return {
loggedIn: ''
}
},
computed: {
returnMessage: function() {
return this.$store.state.loggedIn
}
},
methods: {
testLogin(){
console.log('foo');
this.$store.commit('truthify');
}
},
store: store,
}
</script>
I'm not sure what the issue is.
Related
I have a phone mask. More precisely, an error instead of a mask.
I really can't figure out why the error occurs because it is completely uninformative!!!
<template>
<input type="text" v-model="value" v-mask="'#-#-#'" />
</template>
<script>
import { ref, defineComponent } from "vue";
export default defineComponent({
setup() {
const value = ref("");
return { value };
},
watch: {
value(n) {
this.$emit("input", n);
},
},
});
</script>
https://codesandbox.io/s/musing-resonance-dyl63c?file=/src/App.vue
If you remove the v-mask directive, then everything works as it should. How can I solve the error??
Thank you!
Try to register it locally, it should work :
<template>
<input type="text" v-model="value" v-maska="'#-#-#'" />
</template>
<script>
import { ref, defineComponent } from "vue";
import { maska } from "maska";
export default defineComponent({
setup() {
const value = ref("");
return { value };
},
directives: { maska },
watch: {
value(n) {
this.$emit("input", n);
},
},
});
</script>
Try this way:
in your main.js instead app.directive("v-mask", maska) go with app.use(maska)
in phone.vue instead v-mask="'#-#-#'" go with v-maska="'#-#-#'"
codesandbox
I want to list the array named names of the first object in players using mapState with Vuex. In the current code, the objects in the players are listed according to their titles, but I want to filter them only according to the names in the first object on that page. On second page I want to list them according to the names that I will add to the second object. I hope I was able to explain my problem. How can I do this in the filter? Or what if there is a better way to do this?
Players.vue
<template>
<div class="Players">
<CostumText class="Players-title" tag="h1">Kulüpler</CostumText>
<div class="Players-search">
<input type="text" v-model="search" placeholder="Kulüp ara.." />
<label>Futbolcu ara:</label>
</div>
<div class="Players-inner">
<router-link
:to="players.pathName"
class="Players-inner-wrapper"
v-for="players in filteredList"
v-bind:key="players.id"
>
<div class="Players-inner-cards">
<Clubs class="Players-inner-cards-svg" v-bind:name="players.id" />
<CostumText tag="strong" lang="tr" class="Players-inner-cards-text">
{{ players.title }}
</CostumText>
</div>
</router-link>
</div>
<router-view />
</div>
</template>
<script>
import { mapState } from 'vuex'
import CostumText from '#/components/CostumText'
import Clubs from '#/components/Clubs.vue'
export default {
name: 'Players',
components: {
CostumText,
Clubs
},
data() {
return {
search: ''
}
},
computed: {
...mapState(['players']),
filteredList() {
return this.players.filter((player) =>
player.title.toLowerCase().includes(this.search.toLowerCase())
)
}
},
modules: {}
}
</script>
store/index.js
import Vue from 'vue'
import Vuex from 'vuex'
Vue.use(Vuex)
export default new Vuex.Store({
state: {
players: [
{
id: 1,
names: ['kerem', 'sirin', 'ali', 'ayse', 'ahmet'],
title: 'Ali',
pathName: 'ali'
},
{
id: 2,
title: 'Ayse',
pathName: 'ayse'
},
{
id: 3,
title: 'Ahmet',
pathName: 'ahmet'
}
]
},
getters: {},
mutations: {},
actions: {},
modules: {}
})
You can modify the filteredList to be
computed: {
...mapState(['players']),
filteredList() {
const filteredPlayers = this.players.filter(player => {
let flag = false;
if(player.names) {
player.names.forEach(name => {
if(name.toLowerCase().includes(this.search.toLowerCase()) flag = true;
});
}
return flag;
});
return filteredPlayers;
},
Here is how you display names
<div class="Players-inner-cards">
<Clubs class="Players-inner-cards-svg" v-bind:name="players.id" />
<CostumText tag="strong" lang="tr" class="Players-inner-cards-text">
{{ players.names.valueOf() }}
</CostumText>
</div>
I have two components and a basic store as per the docs here: https://v2.vuejs.org/v2/guide/state-management.html#Simple-State-Management-from-Scratch.
I want to make it so that when I type into an input the value in a different component is updated by using the store.
Basic example here.
App.vue
<template>
<div id="app">
<h1>Store Demo</h1>
<BaseInputText /> Value From Store: {{ test }}
</div>
</template>
<script>
import BaseInputText from "./components/BaseInputText.vue";
import { store } from "../store.js";
export default {
// This should reactively changed as per the input
computed: {
test: function() {
return store.state.test;
}
},
components: {
BaseInputText
}
};
</script>
BaseInput.vue
<template>
<input type="text" class="input" v-model="test" />
</template>
<script>
import { store } from "../store.js";
export default {
data() {
return {
test: store.state.test
};
},
// When the value changes update the store
watch: {
test: function(newValue) {
store.setTest(newValue);
}
}
};
</script>
store.js
export const store = {
debug: true,
state: {
test: "hi"
},
setTest(newValue) {
if (this.debug) console.log("Set the test field with:", newValue);
this.state.test = newValue;
}
};
I want to make it so that when I type a string into the input the test variable in App.vue is updated. I'm trying to understand how the store pattern works. I'm aware of how to use props.
I also have a working copy here: https://codesandbox.io/s/loz79jnoq?fontsize=14
Updated
2.6.0+
To make store reactive use Vue.observable (added in in 2.6.0+)
store.js
import Vue from 'vue'
export const store = Vue.observable({
debug: true,
state: {
test: 'hi'
}
})
BaseInputText.vue
<input type="text" class="input" v-model="state.test">
...
data() {
return {
state: store.state
};
},
before 2.6.0
store.js
import Vue from 'vue'
export const store = new Vue({
data: {
debug: true,
state: {
test: 'hi'
}
}
})
BaseInputText.vue
<input type="text" class="input" v-model="state.test">
...
data() {
return {
state: store.state
};
}
Old answer
From documentation However, the difference is that computed properties are cached based on their reactive dependencies.
The store is not reactive
Change to
App.vue
data() {
return {
state: store.state
};
},
computed: {
test: function() {
return this.state.test;
}
},
It looks bad but I don't see another way to make it work
I have a few forms. Every of them have the same logic (validation, sending...) so, I want to create one method to control actions on my forms. For now my code is redundancy, because I have the same methods onSubmit() on every .vue file.
my HTML:
<div id="app">
<myform-one></myform-one>
<myform-two></myform-two>
</div>
my JavaScript (main.js - entry file in webpack):
import Vue from 'vue';
import Myform1 from './myform1.vue';
import Myform2 from './myform2.vue';
new Vue({
el: '#app',
components: {
myformOne: Myform1,
myformTwo: Myform2
}
});
and VUE components files:
myform1.vue:
<template>
<div>
<form #submit.prevent="onSubmit">
<input type="text" v-model="fields.fname11" />
<input type="text" v-model="fields.fname12" />
<button type="submit">submit</button>
</form>
</div>
</template>
<script>
let formfields = {
fname11: '',
fname12: ''
};
export default {
data() {
return {
fields: formfields
}
},
methods: {
onSubmit() {
// code responsible for reading, validating and sending data here
// ...
console.log(this.fields);
}
},
}
</script>
and myform2.vue:
<template>
<div>
<form #submit.prevent="onSubmit">
<input type="text" v-model="fields.fname21" />
<input type="text" v-model="fields.fname22" />
<input type="text" v-model="fields.fname23" />
<button type="submit">submit</button>
</form>
</div>
</template>
<script>
let formfields = {
fname21: '',
fname22: '',
fname23: '',
};
export default {
data() {
return {
fields: formfields
}
},
methods: {
onSubmit() {
// code responsible for reading, validating and sending data here
// ...
console.log(this.fields);
}
},
}
</script>
How can I create and use one, common method submitForm()? And where its code should be (good practice)?
Create a separate file which contains the logic:
// submitForm.js
export default function (fields) {
// code responsible for reading, validating and sending data here
// ...
}
Then use that logic inside the components
import submitForm from "../services/submitForm.js"
...
methods: {
onSubmit() {
submitForm(this.fields)
}
}
Vue3 (with Quasar for me but I'm sure it would work for any framework):
Say you have a parent which contains a number of forms <Forms />:
First create a composable function like so useForms.js:
import { ref } from 'vue'
const forms = ref([])
export function useForms(){
const checkForms = () => {
forms.value.forEach((form) => form.validate()
}
const addFormToFormsArray = (form) => {
forms.value.push(form)
}
return { forms, addFormToFormsArray, checkForms }
}
Then import it into <Forms />:
<template>
<Form />
<Form />
<Form />
<button #click="checkForms">Check Form</button>
</template>
<script setup>
import { useForms } from '../useForms';
const { checkForms } = useForms()
</script>
Finally, inside the <Form />:
<template>
<form ref="form">
.../stuff
</form>
</template>
<script setup>
import { ref, onMounted } from 'vue'
import { useForms } from '../useForms';
const form = ref(null)
onMounted(() => {
addFormToFormsArray(form.value)
})
const { checkForms, addFormToFormsArray } = useForms()
</script>
When performing the check function in the parent, it should go through each form and check for any issues.
There are some options. My favorite is creating a mixin vue docs mixins
export const form_functionality = {
methods: {
on_submit() {
//logic of submit
},
//here we can have other reusable methods
}
}
Then in your components use that mixin as follow:
import { form_functionality } from 'path_of_mixin'
export default {
mixins: [form_functionality]
}
In the end, what mixins has (created, methods, data etc) will be merged to the component
which uses that mixin.
So, practically you can access the mixin method like this.on_submit()
I have a simple component:
<template>
<div id="search__index_search-form">
<input :foo-id="fooId" #keyup.enter="findFoos()" type="text" :value="keyword" #input="updateKeyword"
placeholder="Search for a foo">
<button #click="findFoos()">Search!</button>
{{fooId}}
</div>
</template>
<script>
import {mapState} from "vuex";
export default {
computed: mapState({
keyword: state => state.search.keyword
}),
data: function () {
return {fooId: "all"};
},
methods: {
updateKeyword(e) {
this.$store.commit("setSearchKeyword", e.target.value);
},
findFoos() {
this.$store.dispatch("findFoos");
}
}
};
</script>
I am calling it from nuxt page:
<template>
<searchbar v-bind:fooId="500"/>
</template>
<script>
import searchBar from "~/components/search-bar.vue";
export default {
components: {
'searchbar': searchBar
}
};
</script>
This results in:
<div id="search__index_search-form" fooid="500"><input shop-id="all" type="text" placeholder="Search for a foo"><button>Search!</button>
all
</div>
Question is, why is fooId bound to "div.search__index_search-form" and not to input? And how come {{fooId}} results in "all" (default state), and not "500"?
fooId is rendered on div#search__index_search-form because you do not declare fooId as a property of the component. Vue's default behavior is to render undeclared properties on the root element of the component.
You need to declare fooId as a property.
export default {
props: {
fooId: {type: String, default: "all"}
},
computed: mapState({
keyword: state => state.search.keyword
}),
methods: {
updateKeyword(e) {
this.$store.commit("setSearchKeyword", e.target.value);
},
findProducts() {
this.$store.dispatch("findFoos");
}
}
};
I'm not sure what you are really trying to accomplish though.
<input :foo-id="fooId" ... >
That bit of code doesn't seem to make any sense.