Confused about vuex getters: How to return a function - vuex

According to the Vuex documentation, You can also pass arguments to getters by returning a function. enter link description here
But I have a problem.In my case, there is a student list, and I want to find the student by id. Below is my code:
//store.js
export const store = {
state: {
students: [
{ name: 'Wang Pengfei', id: 0, sex: 'male' },
{ name: 'Tang Weijuan', id: 1, sex: 'female' },
{ name: 'Xiao Ming', id: 2, sex: 'male' },
{ name: 'Xiao Hong', id: 3, sex: 'female' }
]
},
getters: {
getStudentById: function(state){
return function(id){
return state.students.find(st => st.id === id);
}
}
}
};
But When I try to access this getter in my component, I get a text string of return function.
<template>
<div>
<input name="indexInput" #input="inputChange" value="0"/>
<!-- This line will be rendered as 'The students you find is function (id) { return state.students.find(function (st) { return st.id === id; }); }'-->
<span>The students you find is {{objectStudent}}</span>
</div>
</template>
<script>
export default {
data() {
return {
stId: 0
};
},
methods: {
inputChange(event) {
this.stId = event.target.value;
}
},
computed: {
//return the code of function as a text string, why???
objectStudent() {
return this.$store.getters.getStudentById(this.stId);
}
}
};
</script>
Can anyone help me? Thanks!

Try this:
getters: {
getStudentById: (state) => (id) => state.students.find(st => st.id === id);
}

Finally, I solve the problem.The way I create the store is wrong, I should use new Vuex.Store() instead of creating directly by {}.

Related

Recursive method in VueJS

I'm creating a recursive method in Nuxt, can I do it?
Here is my component:
<script>
export default {
data() {
return {
items: [],
auxitems: [],
}
},
methods: {
orderRecursive(items, auxitems) {
items.data.forEach((element) => {
auxitems.push(element)
})
if (items.child.length > 0) {
this.orderRecursive(items.child, auxitems)
} else {
//
}
},
},
}
</script>
The struct items is like:
items= [
data: [{array}],
child: [{data, child}]
]
My intention is order all data in one array, then, I can show in view.
My method orderRecursive() is not working, can you tell me why?

Vuejs - Resolve deep nested v-model property at runtime

I have a dynamic form where the v-model of the input control is resolved at runtime. It works for simple 0 or 1 level deep objects. But I do not know how to get it working for nested properties that are more than 1 level deep.
My HTML is like:
<div v-for="element in elements" v-bind:key="element.name">
<q-input v-model="inputdata[element.model]"></q-input>
</div>
Javascript
<script>
export default {
data () {
return {
inputdata: {
account: {
name: '',
address: {
street: ''
}
},
},
}
},
}
</script>
Array with data:
elements: [
{
type: 'text',
hint: 'Address',
label: 'Street',
model: 'account.address.street', // does not work. i want to be able to set any level deep property
name: 'street'
}
]
As long as I try to set the property at 0 or 1st level (inputdata or inputdata.account), it works.
How to get a property as deep as inputdata.account.name or inputdata.account.address.street to work?
maybe you can use custom iterative methods instead of v-model
const getValueByModel = (model, data) => {
if(model.includes('.')){
model = model.split('.');
let key = model.shift();
return getValueByModel(model.join('.'), data[key]);
}
else{
return data[model];
}
}
const setValueByModel = (model, oldObject, newValue) => {
if(model.includes('.')){
model = model.split('.');
let key = model.shift();
oldObject[key] = setValueByModel(model.join('.'), oldObject[key], newValue);
}
else{
oldObject[model] = newValue;
}
return oldObject;
}
const getValueByModel = (model, data) => {
if(model.includes('.')){
model = model.split('.');
let key = model.shift();
return getValueByModel(model.join('.'), data[key]);
}
else{
return data[model];
}
}
const setValueByModel = (model, oldObject, newValue) => {
if(model.includes('.')){
model = model.split('.');
let key = model.shift();
oldObject[key] = setValueByModel(model.join('.'), oldObject[key], newValue);
}
else{
oldObject[model] = newValue;
}
return oldObject;
}
new Vue({
el: '#app',
data () {
return {
inputdata: {
account: {
name: '',
address: {
street: ''
}
},
},
elements: [
{
type: 'text',
hint: 'Name',
label: 'Name',
model: 'account.name',
name: 'name'
},
{
type: 'text',
hint: 'Address',
label: 'Street',
model: 'account.address.street',
name: 'street'
},
]
}
},
methods: {
getInputValue(model){
return getValueByModel(model, this.inputdata);
},
updateInputValue(model, event){
let newValue = event.target.value;
this.inputdata = {...setValueByModel(model, this.inputdata, newValue)};
}
}
});
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.5.17/vue.js"></script>
<main id="app">
<div v-for="element in elements" v-bind:key="element.name">
<input :value="getInputValue(element.model)"
#input="updateInputValue(element.model, $event)"
:placeholder="element.name"/>
</div>
{{ inputdata }}
</main>

How to pass values from state in vuex post request

I am collecting data using get and set for my form. I want to post the states to the api.
How can I move the states or group them somehow so I can pass them as to action?
state: {
firstname: "",
lastname: "",
},
mutations: {
setFirstName(state, value) {
state.firstname = value
},
setLastName(state, value) {
state.lastname = value
},
So it looks like this:
sendInfo({commit}, object) {
axios.post('API_URL', object)
.then((response) => {
...
})
}
computed: {
firstname: {
get() {
return this.$store.state.firstname
},
set(value) {
this.$store.commit("setFirstName", value)
}
},
or am I approaching this wrongly?
It's probably best to put these values inside a state object like:
state: {
user: {
firstname: '',
lastname: ''
}
}
You can set the object in an action
actions: {
setData({ commit }, payload) {
commit('SET_DATA', payload);
}
},
mutations: {
SET_DATA(state, payload) {
state.user = payload;
}
}
It also makes it concise when using mapState:
computed: {
...mapState(['user'])
}

Vue/AgGrid: Floating Filter Component, Array of Objects Cell Data

In my AgGrid data, I have a column which has a value of array of objects like this:
...
media:
[
{ title: 'Facebook', site: 'http://www.facebook.com'},
{ title: 'Twitter', site: 'http://www.twitter.com'}
{ title: 'Instagram', site: 'http://www.instagram.com'}
]
...
I managed to show in by cellRenderer like this
'Facebook, Twitter, Instagram'
But my problem is my floating filter , I don't know how to filter all columns which has for example has 'Facebook' media.
Here's my custom floating filter component:
import Vue from 'vue'
export default Vue.extend({
template: `
<input type="text" #change="valueChanged($event)"/>
`,
data: function() {
return {
currentValue: ''
}
},
beforeMount() {},
mounted() {},
methods: {
valueChanged(event) {
this.currentValue = event.target.value
this.params.onFloatingFilterChanged({
model: this.buildModel()
})
},
onParentModelChanged(parentModel) {
this.currentValue = !parentModel ? 0 : parentModel.filter
},
buildModel() {
if (this.currentValue === 0) {
return null
}
return {
filterType: 'text',
type: 'equalsTo',
filter: this.currentValue,
filterTo: null
}
}
}
});

Vuex working wrong

my vuex looks like:
state: {
loadedUsers: [
{ id: 10, classId: 1, name: 'X' },
{ id: 11, classId: 1, name: 'Y' },
{ id: 13, classId: 2, name: 'Z' }
]
}
getters: {
loadedUsers (state) {
return (classId) => {
return state.loadedUsers.find((user) => {
return user.classId === classId
})
}
}
}
and my computed:
computed: {
users () {
return this.$store.getters.loadedUsers(1)
}
}
its just returns { id: 10, classId: 1, name: 'X' }
also when I use like
this.$store.getters.loadedUsers(this.$route.params.classid)
the classid reaching but returns empty
What could be the problem?
That is because Array.prototype.find() returns the value of the first element that matches. You should be using Array.prototype.filter() instead. Also, you can unwrap your function/method call by one layer:
getters: {
loadedUsers (state) {
return classId => state.loadedUsers.filter((user) => {
return user.classId === classId
})
}
}