Vuex: getters return always initial value - vue.js

I try to get the value of the vuex getters but I always get the initial value.
My Code:
export default {
state:{
transuser:{
Name: '1',
Email: '2',
Role: '3',
Email_Verified: '4',
Created:'5',
Updated:'6',
Edit_User:'7',
Delete_User:'8'
}
},
mutations:{
transusers(state,data) {
state.transuser.Name = data.Name ;
state.transuser.Email = data.Email ;
state.transuser.Role = data.Role ;
state.transuser.Email_Verified = data.Email_Verified;
state.transuser.Created = data.Created ;
state.transuser.Updated = data.Updated ;
state.transuser.Edit_User = data.Edit_User ;
state.transuser.Delete_User = data.Delete_User ;
return state.transuser;
}
},
getters:{
getTranslationUser(state){
return state.transuser
}
},
actions:{
loadTranslationUser(context){
axios.get("/t/gettransuser")
.then((response)=>{
context.commit("transusers",response.data);
})
.catch((error)=>{
console.log(error)
})
}
}
}
In my Component
mounted(){
this.$store.dispatch("loadTranslationUser");
},
I have a method
T(t)
{
return this.$store.getters.getTranslationUser[t];
}
Then I use it in my component:
columns: [
{
label: 'ID',
name: 'id',
orderable: true,
},
{
label: this.T('Name'),
name: 'name',
orderable: true,
},
etc....
But I get always the initial value 1,2,3,4,5 etc....
But if I do console.log(this.$store.getters.getTranslationUser) in my method T I see
{…}
Created: "Toegevoegd Op"
Delete_User: "Gebruiker Verwijderen"
Edit_User: "Gebruiker Aanpassen"
Email: "E-mail"
Email_Verified: "E-mail Geverifieerd"
Name: "Naam"
Role: "Rol"
Updated: "Aangepast Op"
So the correct values are there but I can't use them.
So what Am I doing wrong?

I believe you have columns in data field:
data() {
return {
columns: [...]
}
}
Move it to computed and it will pick up changes:
computed: {
columns() {
return [...]
}
}

Related

Data not being passed from Child Data to Parent Props

I have a Request Form Component, and within this request form Component I have a Dropdown Menu Component, which I will link both below. All values in my table are pushed into an object upon hitting the Submit Button. However my dropdown selection is only being picked up by my console.log and not being pushed into the Object.
I'm not so familiar with Vue, so I'm not sure what direction to go in for fixing this. I'll attach the relevant (?) pieces of code below.
Parent Component:
<SelectComponent :selected="this.selected" #change="updateSelectedValue" />
export default {
fullScreen: true,
name: 'CcRequestForm',
mixins: [BaseForm],
name: "App",
components: {
SelectComponent,
},
data() {
return {
selected: "A",
};
},
props: {
modelName: {
default: 'CcRequest',
},
parentId: {
type: Number,
default: null,
},
},
mounted() {
this.formFields.requester.value = this.currentRequesterSlug;
},
destroyed() {
if (!this.modelId) return;
let request = this.currentCcRequest;
request.params = request.params.filter(p => p.id)
},
computed: {
...mapGetters(['ccTypesForRequests', 'currentRequesterSlug', 'currentCcRequest']),
ccTypesCollection() {
return this.ccTypesForRequests.map((x)=>[x.slug, this.t(`cc_types.${x.slug}`)]);
}
},
methods: {
addParam() {
this.addFormFields(['params'], {
slug: '',
name: '',
isRequired: true,
description: '',
typeSlug: '',
selected: ''
});
},
deleteParam(idx){
this.removeFormFields(['params', idx]);
},
restoreParam(idx){
this.restoreFormFields(['params', idx])
},
$newObject() {
return {
slug: '',
name: '',
isAbstract: false,
requester: '',
description: '',
status: 'inactive',
params: [],
selected: ''
};
},
$extraPrams() {
return {
parentId: this.parentId,
};
},
updateSelectedValue: function (newValue) {
this.selected = newValue;
},
},
watch: {
selected: function (val) {
console.log("value changed", val);
},
},
};
Child Component:
<script>
export default {
name: "SelectComponent",
props: {
selected: String,
},
computed: {
mutableItem: {
get: function () {
return this.selected;
},
set: function (newValue) {
this.$emit("change", newValue);
},
},
},
};
You have to define the emit property in the parent component, or else it won't know what to expect. That would look like:
<SelectComponent :selected="this.selected" #update-selected-value="updateSelectedValue" />
Check out this tutorial for more information: https://www.telerik.com/blogs/how-to-emit-data-in-vue-beyond-the-vuejs-documentation
To update selected property inside the object, in this constellation, you need to update object property manually upon receiving an event, inside of updateSelectedValue method. Other way could be creating a computed property, since it's reactive, wrapping "selected" property.
computed: {
selectedValue () {
return this.selected
}
}
And inside of object, use selectedValue instead of selected:
return {
...
selected: selectedValue
}

TreeGrid extension for DataTables - how to get a checkbox added after name?

I found a TreeGrid extension for DataTables:
https://homfen.github.io/dataTables.treeGrid.js/
but instead of the name I would like to add a column between name and position and place a checkbox here.
However when I do this e.g.:
var columns = [
{
title: '',
target: 0,
className: 'treegrid-control',
data: function (item) {
if (item.children) {
return '<span>+<\/span>';
}
return '';
}
},
{
title: 'Name',
target: 1,
data: function (item) {
return item.name;
}
},
{
defaultContent: '',
target: 2,
className: 'select-checkbox',
function(item) {
return item;
}
},
{
title: 'Position',
target: 3,
data: function (item) {
return item.position;
}
},
{
title: 'Office',
target: 4,
data: function (item) {
return item.office;
}
},
{
title: 'Extn.',
target: 5,
data: function (item) {
return item.extn;
}
},
{
title: 'Start date',
target: 6,
data: function (item) {
return item.start;
}
},
{
title: 'Salary',
target:7,
data: function (item) {
return item.salary;
}
}
];
I get an extra column but when checking the parent does not select all underlying children rows.
Anyone have an idea how to establish this?
Edit: updated the columns definition.
When I add a button to read the selected values e.g.:
dom: 'Bfrtip',
select:true,
buttons: [
{
text: 'Alert selected',
action: function(e, dt, node, config) {
var data = table.rows({
selected: true
}).data().toArray();
var i;
var text = new Array();
for (i = 0; i < data.length; i++) {
text.push(data[i].name);
}
alert("you selected: " + text.join(",") );
console.log("text---" + text.join(","));
}
}
]
the table starts to behave oddly for example: the selection of underlying children stops.

Add extra field on items of <v-data-table>

I have medications object as follow:
medications: [
{
'name': 'abc',
'id': naks23kn,
'resident': //this is resident id, resident is another object
.........
},
{.......},.....
]
I wanted to add another field residentName on this object list or is there any way so that I can display 'residentName' in the v-data-table ?:
medications: [
{
'name': 'abc',
'id': naks23kn,
'resident': //this is resident id, resident is another object
'residentName': 'ad' //set this new field
.........
},
{.......},.....
]
I am using `v-data-table> as :
<v-data-table
:headers="headers"
:items="medications"
:items-per-page="20"
:search="search"
class="elevation-23"
>
Now I want to add an residentName field based on the resident field. For this I did the following:
export default {
data() {
return {
medications: [],
}
},
computed: {
...mapGetters([
'allMedications', //this is used to get all medication from medication store
'getResidentsById',
]),
},
created() {
this.get_resident_list(),
this.get_registered_medication_list();
},
methods: {
...mapActions([
'get_registered_medication_list', //this is used to call API and set state for medication
'get_resident_list', //this is used to callAPI and set state for resident
]),
getResidentName(id) {
const resident = this.getResidentsById(id)
return resident && resident.fullName
},
},
watch: {
allMedications: {
handler: function () {
const medicationArray = this.allMedications;
console.log("Created this");
this.medications = medicationArray.map(medication => ({
...medication,
residentName: this.getResidentName(medication.resident)
})
);
},
immediate: true
},
}
}
In header
headers: [
{ text: 'Medication Name', value: 'name' },
{ text: 'Resident', value: 'residentName' },
]
This is in resident.js getter module
getResidentsById: (state) => (id) => {
return state.residents.find(resident => resident.id === id)
}
Edit: This is working, i.e I am getting residentName when the page is created but if I refresh the page then I get residentName=undefined
You can use map to add new prop to your each item in array
let medications = [{
name: 'abc',
id: 'naks23kn',
resident: 1
}]
medications.map(item => item.residentName = "Your Resident Name")
console.log(medications)
This should work
watch: {
allMedications: {
handler: function() {
const medicationArray = this.allMedications;
console.log("Created this");
this.medications = medicationArray.map(medication => medication.residentName = this.getResidentName(medication.resident)));
},
immediate: true
},
}

Reset a const variable to its default value in vue

How can I reset the value of my constant variable in vue? Here is what I meant:
data(){
const _hdrList = [
{
label: 'start_time',
value: 'start_time'
},
{
label: 'name',
value: 'name'
},
{
label: 'another',
value: 'another'
},
];
const _cboList = [
{start_time:''},
{name:''},
{another:''},
];
return{
hdrList:_hdrList,
headercbo:_cboList,
columns:[],
}
}
After that, I access it using the following:
<tr>
<th v-for="(col, index) in columns" :key="index.id">
<ui-select
:options="hdrList"
v-model="headercbo[index][hdrList[index]['label']]"
></ui-select>
</th>
</tr>
The output of this one is like this:
And when I click the clear button, this combo lists are not reverting back to default which it displays an empty or no selected value. Here's how I do it.
clearFields(){
this.columns = [];
this.headercbo = [];
}
But this one does not clear the fields, they still have the previous selected value with them. How can I totally clear them up and set backs to default.
Move the constant out of data.
During reset, you've reassign the default headercbo value with the constant value.
const _hdrList = [
{
label: 'start_time',
value: 'start_time'
},
{
label: 'name',
value: 'name'
},
{
label: 'another',
value: 'another'
},
];
const _cboList = [
{start_time:''},
{name:''},
{another:''},
];
export default {
data(){
return{
hdrList:_hdrList,
headercbo:_cboList,
columns:[],
}
},
clearFields() {
this.columns = [];
this.headercbo = _cboList;
}
}
Put what you have in your data function into a method named initialData, then use that function in your data function and in your clearFields method.
data() {
return this.initialData();
},
methods: {
initialData() {
const _hdrList = [{
label: 'start_time',
value: 'start_time'
},
{
label: 'name',
value: 'name'
},
{
label: 'another',
value: 'another'
},
];
const _cboList = [{
start_time: ''
},
{
name: ''
},
{
another: ''
},
];
return {
hdrList: _hdrList,
headercbo: _cboList,
columns: [1,2],
}
},
clearFields() {
this.columns = [];
this.headercbo = this.initialData().headercbo;
}
}

Computed property depends on vuex store. How to update the cached value?

The value of this.$store.state.Auth.loginToken is modified by one of its child components. The initial value of this.$store.state.Auth.loginToken is undefined. But still, the update in its value has no effect in the cached value of navItems thus it always returns the second value.
computed: {
navItems () {
return this.$store.state.Auth.loginToken != undefined ?
this.items.concat([
{ icon: 'add', title: 'Add new journal entry', to: '/' },
{ icon: 'power_settings_new', title: 'Logout', to: '/logout'}
]) :
this.items.concat([
{ icon: 'play_arrow', title: 'Login', to: '/login' }
])
}
}
Is there a better way to keep a watch on this.$store.state.Auth.loginToken so that it can be used same as navItems?
I created a basic example of how you can use vuex getters and Auth token (codepen):
const mapGetters = Vuex.mapGetters;
var store = new Vuex.Store({
state: {
Auth: {
loginToken: ''
},
menuItems: [
{ icon: 'home', title: 'Home', to: '/' },
{ icon: 'about', title: 'About', to: '/about' },
{ icon: 'contact', title: 'Contact', to: '/contact' }
]
},
mutations: {
SET_LOGIN_TOKEN(state, data) {
state.Auth.loginToken = 1
}
},
getters: {
menuItems(state, getters) {
if(state.Auth.loginToken !== '') {
return state.menuItems.concat([{
icon: 'profile', title: 'Profile', to: '/profile'
}])
}
return state.menuItems
},
loggedIn(state) {
return state.Auth.loginToken !== ''
}
},
actions: {
doLogin({commit}) {
commit('SET_LOGIN_TOKEN', 1)
}
}
});
new Vue({
el: '#app',
store,
data: function() {
return {
newTodoText: "",
doneFilter: false
}
},
methods: {
login() {
this.$store.dispatch('doLogin')
}
},
computed: {
...mapGetters(['menuItems', 'loggedIn'])
}
})
This is just an example so you can ignore the actual login action. Also, the store should be a directory, the getters, mutations and actions should have their own files which are then imported in the index.js in the store like in this example