Vuex Getters doesn't call state - javascript

I trying to return back sorted data (which is the already defined state) in a list with the help of a getter, then assign it to the html list in my vue, but it seems it's empty when I check with the vuex tools.
I don't know what am doing wrong.
Below is my store.js file
export default {
namespaced: true,
state:{
displayChatMessages: [],
},
mutations:{
create(state, payload) {
state.displayChatMessages.push(payload)
},
reset(state){
state.displayChatMessages = []
},
},
actions :{
getAllData:({commit}, payload) => {
commit('create',payload)
},
},
getters:{
filteredChatMessages: state => (chatID) => {
return state.displayChatMessages[0]
.filter(el => el.groupid === chatID).sort((l,r)=> l.timestamp - r.timestamp)
},
},
}
Then, after, I call it in the computed area like below :
...mapGetters('chatMessages',['filteredChatMessages']),
Then , I call the Getter inside my function , like below :
getFilteredMessages: function() {
let vm = this
return vm.filteredChatMessages(vm.groupID)
},
Then afterwards, then I set the getFilteredMessages() to the list , getFilteredMessages() , is also defined in the computed section.
But when I look into my vuex tools , I don't see it as an array :
What am I doing wrong ?

Related

Vue select all checkbox bad performance

I have a list objects displayed, each having a checkbox to select it. I also have a checkbox at the top to select the checkbox for every object, kinda like this (assume [ ] is a checkbox):
[ ] Select all
[ ] Object 1
[ ] Object 2
[ ] Object 3
The problem I have is when I have about 100 objects and clicking "Select all", the web page freezes for a good few seconds. There is also a search bar to filter the object, but I tested this by removing it and the performance is just as slow. Each object has a property selected so we know which object is selected. Below are some snippets of my code:
HTML:
<checkbox-input
id="documentSelectAll"
:model-value="operatingRows.length === 0 ? false : allSelected"
#update:modelValue="allSelectPressed" // Calls vuex function below
/>
---
<tr
v-for="(row, index) in operatingRows"
:key="index"
>
<document-table-row
:row-idx="index"
:row-data="row"
:fields="row.fields"
:hidden-column-indices="hiddenColumnIndices"
#toggleSelectedOnRow="toggleSelectedOnRow(row.id)" // Calls vuex to select individual row
/>
</tr>
Computed properties:
operatingRows() {
const showRow = (r) => {
// Some search code, irrelevant here
};
return this.sorted.filter(showRow); // 'sorted' comes from vuex
},
selectedRows() {
return this.operatingRows.filter((r) => r.selected);
},
numSelected() {
return this.selectedRows.reduce((prev, cur) => (cur.selected ? prev + 1 : prev), 0);
},
allSelected() {
return this.numSelected === this.operatingRows.length;
},
Vuex store:
getters: {
...storeStateGetters,
sorted: (state) => state.sorted,
},
---
mutations: {
...storeStateMutations,
SET_ALL_SELECTED_ON_SORTED(state, isSelected) {
state.sorted.map((r) => {
const rn = r;
rn.selected = isSelected;
return rn;
});
},
},
I think it might be to do with the fact that there are too many computed properties? I tried removing them individually (and the associated code) but the performance still seems bad, thus I am not able to pin point the issue to any particular piece of code, rather I think it's to do with the architecture as a whole.
Any help appreciated.
Turns out it was because of the mutation. To fix this, the mutation code was moved to an action which calls a mutation to set the state of the sorted array.
selectOnSorted: ({ commit, rootGetters }, isSelected) => {
const selectedSorted = rootGetters['documents/sorted'].map((doc) => ({
...doc,
selected: isSelected,
}));
commit('SET_SORTED', selectedSorted);
},

how to keep calculating each time the page is refreshed

I cannot assign the value of the calculated user data to the object in the data, but the data is lost when the page is refreshed.
import Vuetify from "vuetify"
import {
UserData
} from "../../store/userModule";
import jsonDict from "../../jsonFiles/data.json"
import jsonfile from "../../jsonFiles/jsonfile";
export default {
name: "userProfileUpdate",
data() {
return {
selected: "Choose Province",
rules: [
value => !!value || 'Bu alan boş bırakılamaz',
value => (value || '').length <= 20 || 'Max 20 characters',
value => {
const pattern = /^(([^<>()[\]\\.,;:\s#"]+(\.[^<>()[\]\\.,;:\s#"]+)*)|(".+"))#((\[[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}])|(([a-zA-Z\-0-9]+\.)+[a-zA-Z]{2,}))$/
return pattern.test(value) || 'Geçersiz e posta'
},
],
options: jsonDict.Gender,
options2: jsonDict.educational_status,
educational_status: '',
gender: '',
birthday: '',
email: '',
phone_number: '',
username: '',
first_name: '',
last_name: '',
profileData: {
}
}
},
created() {
this.$store.dispatch('initUserData')
this.$store.dispatch('inijson')
},
I have tried many ways it disappears when the page is refreshed even creating computed data but somehow it could not keep the data on the screen after the page refresh
computed: {
genderq() {
for (var i in this.$store.getters.user) {
return this.$store.getters.user[i]
}
return this.$store.getters.user
},
userdata() {
for (const i in this.$store.getters.getUser) {
var data = this.$store.getters.getUser[i]
this.username = data['username']
//this.$store.dispatch('getJsonData',data['gender'])
return data
}
return this.$store.getters.getUser
},
},
Hey you could try using localStorage or sessionStorage, and add the mounted() property to your component (this property is fired when the component is mounted) and then you could affect your data() values from the localStorage for example
data() => { myData: 0 },
computed()=>{
storeValue(){
localStorage.setItem('data', this.myData)
}
},
mounted() =>{
localStorage.getItem('data') ? this.myData = localStorage.getItem('data') : null //null because in data() myData has a default value but you can say this.myData = 0
}
With the mounted lifecycle property and the browser storage, you will have a trace of every value you want to keep between 2 refreshes (look for both localstorage and sessionStorage as they don't last the same time), basically, you can have a method (not a computed) that stores the object you want in the storage, then you can call this method at the end of every computed property that modifies the data you want to keep between refreshes.
edit: here is a link to help you to understand the lifecycle of a vue component it might help you later too if you want to create more complex components, lifecycle diagram
Best regards

update dynamic object in redux using spread operator

I am trying to update an object in redux using spread operator but I am not being able to.
Initial state is an empty object because category is received dynamically from api call.
pages and data are both objects which i want to update using spread operator (or whatever works best)
state = {
[category]: {
pages: {
key: value(array)
},
data: {
key: value(array)
}
}
}
At my reducer I try to update it like this
return {
...state,
[category]: {
...state[category],
pages: { ...state[category].pages, pages },
data: { ...state[category].data, doctors },
total: total,
},
};
but i get "error: TypeError: Cannot read property 'pages' of undefined"
What am I doing wrong and how can I update them correctly?
Because state.category is undefined when you fetch this category for the first time. You can fix it like that:
return {
...state,
[category]: state.category
? {
...state[category],
pages: { ...state[category].pages, pages },
data: { ...state[category].data, doctors },
total: total,
}
: {
pages,
data: doctors,
total,
},
};

How to put return value into another return value in JS vue

I want the "topic1" to be the value of my breed name and key, but when I try to put this.topic1 to replace the manual typing, it shows nothing.
Or there are any other method to have my button name same as my retrieve API param, and sent it name when I click it?
new Vue({
el: '#app2',
components: { Async },
data() {
return {
topic1: null,
topic2: null,
currentBreed: 0,
breeds: [
{ name: this.topic1 , key: this.topic1 },
{ name: "German Shepherd", key: "germanshepherd" },
{ name: "Husky", key: "husky" },
{ name: "Pug", key: "pug" },
{ name: "(Error)", key: "error" },
]
}
},
async created() {
try {
this.promise = axios.get(
"https://k67r3w45c4.execute-api.ap-southeast-1.amazonaws.com/TwitterTrends"
);
const res = await this.promise;
this.topic1 = res.data[0].Trends;
this.topic2 = res.data[1].Trends;
} catch (e) {
console.error(e);
}
},
async mounted () {
let test = this.topic1;
},
computed: {
breedKey() {
return this.breeds[this.currentBreed].key;
}
}
})
There are several problems here.
The data function is called just once, when the corresponding Vue instance is created. Within that function you can get a reference to its Vue instance via this. At that point some properties, such as those corresponding to props, will already exist. However, others won't.
The object returned from data is used to create new properties on the instance. In this case you're creating 4 properties: topic1, topic2, currentBreed and breeds. Vue creates those properties based on that returned object, so they won't exist until after the data function is run.
So when you write { name: this.topic1 , key: this.topic1 }, within that data function you're attempting to access a property called topic1 that doesn't exist yet. As such it will have a value of undefined. So you're creating an entry equivalent to { name: undefined , key: undefined },.
Further, there is no link back to topic1. That object won't be updated when the value of topic1 changes.
It's also worth noting a few points about timing.
The data function will be called before the created hook, so the axios call isn't made until after the data properties are populated.
An axios call is asynchronous.
Using await may make the code a little easier to read but the 'waiting' is mostly just an illusion. The remaining code inside the function won't run until the awaited promise is resolved but that won't cause anything outside of the function to wait. await is equivalent to using then.
The component will render just after the created hook is called. This is synchronous, it won't wait for the axios request. The mounted hook will then be called, all before the axios call has completed.
All of this means you may need to adjust your template to handle the case where the axios call hasn't completed yet as it will initially render prior to the values of topic1 and topic2 being available.
Specifically addressing the breeds property you have a few options. One is to inject the values in once the value has loaded:
breeds: [
{ name: "" , key: "" }, // Initially empty values
{ name: "German Shepherd", key: "germanshepherd" },
// ...
const res = await this.promise;
this.topic1 = res.data[0].Trends;
this.topic2 = res.data[1].Trends;
this.breeds[0].name = this.breeds[0].key = this.topic1;
Another is to use a computed property for breeds (you'd remove it from the data for this):
computed: {
breeds () {
return [
{ name: this.topic1 , key: this.topic1 },
{ name: "German Shepherd", key: "germanshepherd" },
{ name: "Husky", key: "husky" },
{ name: "Pug", key: "pug" },
{ name: "(Error)", key: "error" },
]
}
}
As we're using a computed property it will be updated when topic1 changes as it's a reactive dependency.
Using a computed property is probably the most natural solution in this case but there are other tricks you can use to get this to work.
For example, you could use property getters for the two properties in that first breed object (that's JavaScript property getters, nothing to do with Vue):
data () {
const vm = this;
return {
topic1: null,
topic2: null,
currentBreed: 0,
breeds: [
{
get name () {
return vm.topic1;
},
get key () {
return vm.topic1;
}
},
{ name: "German Shepherd", key: "germanshepherd" },
{ name: "Husky", key: "husky" },
{ name: "Pug", key: "pug" },
{ name: "(Error)", key: "error" },
]
}
},
I'm not advocating this approach for your use case but it is an interesting way to do it that can sometimes be useful. The key thing to note is how the dependency on topic1 is evaluated only when the properties name and key are accessed, not when the data function is executed. This allows topic1 to be registered as a dependency of whatever is accessing name and key, e.g. during rendering.

Update dynamic components disabled state based on Vuex state value

I have no idea if what I'm doing is correct or not, but here's a simplified version of what I'm trying to do:
I want to have 3 file inputs, with the 2nd and 3rd disabled until the 1st one has had a file selected.
I've tried to do is set the Vuex state variable to whatever the first file input is has selected, but upon doing that the other 2 inputs don't update their disabled state.
I have some file inputs that are created dynamically, like so:
Vue.component('file-input', {
props: ['items'],
template: `<div><input type="file" v-on:change="fileSelect(item)" v-bind:id="item.id" v-bind:disabled="disabledState"></div>`,
methods: {
fileSelect: function(item) {
store.commit('fileSelect', file);
}
},
computed: {
disabledState: function (item) {
return {
disabled: item.dependsOn && store.getters.getStateValue(item.dependsOn)
}
}
}
}
The data for the component is from the instance:
var vm = new Vue({
data: {
items: [
{ text: "One", id: "selectOne" },
{ text: "Two", id: "selectTwo", dependsOn: "fileOne" },
{ text: "Three", id: "selectThree", dependsOn: "fileOne" }
}
});
Now, notice the "dependsOn". In the Vuex store, I have a corresponding state item:
const store = new Vuex.Store({
state: {
files: [
{
fileOne: null
}
]
},
mutations: {
fileSelect(state, file) {
state.files.fileOne = file;
}
},
getters: {
getStateValue: (state) => (stateObject) => {
return state.files.findIndex(x => x[stateObject] === null) === 0 ? true : false;
}
}
});
Now, the above works when everything is first initialized. But once the first input has something selected, the other two inputs don't change.
I'm not sure how to update the bindings once a mutation of the state occurs.
I think you need to refactor your mutation to make the state property mutable, like this:
fileSelect(state, file) {
Vue.set(state.files[0].fileOne, file);
}
Well, I figured it out...
Because my state object is an array of objects, I can't just change one of the property's values with state.files.fileOne. I needed to do state.files[0].fileOne.

Categories

Resources