My filtered array does not output anything. What am I missing? - vuejs2

I followed the Vue documentation on filtering arrays, but it seems like I must have missed something.
I am testing an array which has three items with two conditions: a name and a boolean. I wanted to test filtering by making a computed property that only returns the name of an item if the boolean value of that item is true.
I am not getting any output, but I am not getting any errors in the console either, so I am unsure of what the issue is.
<div v-for="array in filteredDataTest">
{{ array.name }}
</div>
data() {
return {
testArray: [
{
name: 'Bob',
isTrue: false
},
{
name: 'Mary',
isTrue: true
},
{
name: 'Paul',
isTrue: false
}
]
};
},
computed: {
filteredDataTest() {
this.testArray.filter(user => {
if(user.isTrue) {
return user
}
})
},
},

You should return within the computed getter method. Otherwise you can't see any result from method.
computed: {
filteredDataTest() {
return this.testArray.filter(user => user.isTrue);
},
}

Related

How do you push an object into another object when the data within it gets changed?

I have a very large array of objects containing various errors logs. There are 1015 objects in total. At the moment I am saving the entire array every time I make a small change to a value in one of the objects. This leads to timeout errors because it takes too long to go through the whole array.
So instead I would like to figure out how I can change it so that the program ONLY saves an object if that object has been changed on the frontend.
So if I have 1015 objects and I only change something in object no. 2, then only object no. 2 should be saved on submit.
I was thinking, maybe it would be possible to first let the program look for any changes. Then IF a change has occured it will move that particular object to a new (empty) object, which I can then submit.
So, in my code example, I would like to have this function implemented on the computed property "Fields" which has the key "done". This contains a checkbox that sets the value error.done to true or false. So I would like for the program to check if this specific value has changed. If it has changed from true to false or vice versa I would like to send this object to a new object.
eg. if errors.done is set from true to false, then move the changed object to a new object called changedValue.
<template>
<b-container>
<b-card class="mt-4">
<h5>{{ $t('events') }}</h5>
<b-table
:items="errors"
:fields="fields"
:per-page="[10, 25, 50]"
selectable
:select-mode="'single'"
#row-selected="onRowSelected"
#row-clicked="showModal"
sort-desc
/>
</b-card>
<error-log-entry-modal ref="errorLogEntryModal" :selected-error-log="selectedRows"/>
<button #click="submit">Submit</button>
</b-container>
</template>
<script>
import {errorService} from '#/services/error';
import ErrorLogEntryModal from '#/components/error-log/ErrorLogEntryModal';
import moment from 'moment';
export default {
components: {
ErrorLogEntryModal,
},
props: {
ownerId: String
},
data() {
return {
errors: null,
selectedRows: []
};
},
computed: {
fields() {
return [
{
key: 'done',
label: '',
thStyle: 'width: 1%',
template: {
type: 'checkbox',
includeCheckAllCheckbox: true,
}
},
{
key: 'priority',
label: this.$t('errorLogs.priority'),
sortable: true,
},
{
key: 'creationDateTime',
label: this.$t('creationDateTime'),
formatter: date => moment(date).locale(this.$i18n.locale).format('L'),
sortable: true,
},
{
key: 'stackTraceShort',
label: this.$t('errorLogs.stackTrace'),
sortable: true,
},
{
key: 'errorMessage',
label: this.$t('message'),
sortable: true
},
]
},
},
methods: {
load(){
errorService.getErrorLogs().then(result => {
result.data.forEach(log => log.stackTraceShort = log.stackTrace.substring(0,30));
this.errors = result.data
})
},
submit(){
return errorService.setStatusOnErrorEntryLog(this.errors).then( result => {
console.log(result)
})
},
onRowSelected(fields){
this.selectedRows = fields
},
showModal(){
if (this.selectedRows) {
this.$refs.errorLogEntryModal.show()
}
},
},
created() {
this.load()
},
};
</script>
If I have understood correctly the selected rows correspond to errors.done ? In this case you can just edit the onRowSelected method like this :
onRowSelected(fields){
this.selectedRows.push(fields)
},
Then replace this.errors by this.selectedRows in you're submit method ?

Map array inside computed property

So I wanted to see if I can get some guidance from the community if there is a better way to approach this:
So I have the following vue.js app:
new Vue({
name: 'o365-edit-modal-wrapper',
el: '#o365-modal-edit-wrapper',
data: function() {
const default_apps = [
{
'post_title': 'Excel',
}, {
'post_title': 'Word',
}, {
'post_title': 'SharePoint',
}];
return {
available_list: [],
selected_list: default_apps.map(function(name, index) {
return { name: name.post_title, order: index + 1, fixed: false };
}),
}
},
computed: {
dragOptions() {
// Pass in additional <draggable> options inside the return for both lists.
return {
tag: 'div',
group: 'o365apps',
disabled: !this.editable,
ghostClass: "ghost",
};
},
},
});
The selected_list returns the following items:
I was told that it's bad practice to do array mapping inside the data return, but to instead map inside the computed call - Could someone lead me in the right direction and just see if my code makes sense?
I tried defining an empty array as shown below:
return {
available_list: [],
selected_list:[],
}
& then inside the computed property, I tried accessing it using the following return but wasn't getting any data back:
selected_list() {
return this.default_apps.map(function(name, index) {
return { name: name.post_title, order: index + 1, fixed: false };
});
},
All help is appreciated - Thanks a bunch!
your are almost there except for a few details:
It's ok to map data inside data as long as you put them inside the return object literal data() { return { default_apps: [] } }.
Once default_apps is inside the return object of data, you can access the data inside of it from a computed property using the this keyword: this.default_apps.map()...
new Vue({
name: 'o365-edit-modal-wrapper',
el: '#o365-modal-edit-wrapper',
data: function() {
return {
default_apps: [
{ post_title: 'Excel' },
{ post_title: 'Word' },
{ post_title: 'SharePoint'}
],
available_list: [],
}
},
computed: {
selected_list() {
return this.default_apps.map(function(name, index) {
return { name: name.post_title, order: index + 1, fixed: false };
});
},
dragOptions() {
// Pass in additional <draggable> options inside the return for both lists.
return {
tag: 'div',
group: 'o365apps',
disabled: !this.editable,
ghostClass: "ghost",
};
},
},
});

Vuelidate check array has items on blur

I am using nuxt-vue-select to allow users to select multiple objects form an array locations and then I want to use Vuelidate to try and validate that at least one item in the array has been selected/set on blur however I can not get vuelidate do do this. What am I doing wrong here?
Template
<b-form-group label="Locations" label-for="locations">
<client-only>
<v-select
v-model="userCopy.locations"
name="locations"
filterable
multiple
placeholder="Select locations"
label="label"
:options="locations"
:class="{ 'is-invalid': v.form.locations.$error }"
#blur="v.form.locations.$each[index].$touch()"
/>
</client-only>
</b-form-group>
Script
data() {
return {
form:{
locations: []
}
}
},
validations() {
return {
form: {
locations: {
$each: {
required
}
}
}
}
}
Array data
{ label: 'Avon' },
{ label: 'Bedfordshire' },
{ label: 'Berkshire' },
{ label: 'City of Brighton and Hove' },
{ label: 'City of Bristol' },
For vuelidate you have to use the same filed name as $data, so you need to replace the name form of validations' object to userCopy at first, and apply minLength for your locations length:
validations() {
return {
userCopy: { // change this
locations: {
// ... to try and validate that at least one item in the array
// use minLength to do that
minLength: minLength(1)
$each: {
required
}
}
}
}
}
To deal with array structure, I recommend to try form-validation.js.

Confused about vuex getters: How to return a function

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 {}.

How to map a nested Vuelidate validation object with computed properties in VueJS?

I have a tabs container with multiple forms. Some of the fields in all forms have some complex logic that I didn't want to repeat on each form, so I created a custom component that is used in all forms. I'm trying to use Vuelidate to validate all of my forms but since those field names are the same, and of course have the same validation logic, the Vuelidate validation object is the same in all forms, meaning, if I fill in the email field in formA, then all forms with that same field will also validate correctly, even though the rest of the forms haven't been filled in at all.
I tried to wrap my validations inside an object named as the forms, and this seems to separate all validation logic correctly, but, I have other setup there that prevents me from using data attributes and I use computed attributes instead. As far as I know, the validations object must match the way we access fields data, like, data() { formA: { email } } would match to validation object validations: { formA: { email } }, the problem is, since I'm not using data properties, I don't know how to map computed properties.
This is what I have:
export default {
components: { PhoneField, TopNote, SubmitButton, NameFieldsGroup, EmailField },
validations: {
formA: {
firstName: { required },
lastName: { required },
email: {
required,
email
},
phone: {
required,
length: minLength(10)
}
}
},
created() {
this.$store.commit('setFormValidation', this.$v);
},
data() {
return {}
},
computed: {
firstName: function() {
return this.$store.getters.formState.firstName;
},
lastName: function() {
return this.$store.getters.formState.lastName;
},
email: function() {
return this.$store.getters.formState.email;
},
phone: function() {
return this.$store.getters.formState.phone;
}
}
};
I've been messing around with this for the past several days, but can't figure it out. Anyone can suggest a solution for this?
Figured it out. Not sure why it works but it does now. The fix is to use Vuex's mapState like this:
import { mapState } from 'vuex';
export default {
components: { PhoneField, TopNote, SubmitButton, NameFieldsGroup, EmailField },
validations: {
formA: {
firstName: { required },
lastName: { required },
email: {
required,
email
},
phone: {
required,
length: minLength(10)
}
}
},
created() {
this.$store.commit('setFormValidation', this.$v);
},
data() {
return {}
},
computed: {
...mapState(['formA']),
firstName: function() {
return this.$store.getters.formState.firstName;
},
lastName: function() {
return this.$store.getters.formState.lastName;
},
email: function() {
return this.$store.getters.formState.email;
},
phone: function() {
return this.$store.getters.formState.phone;
}
}
};