pass computed property as method parameter? - vue.js

So I have a store with values:
export const store = new Vuex.Store({
state: {
selectedGradeId: null,
},
getters:{
selectedGradeId: state => {
return state.selectedGradeId
},
},
mutations:{
SET_SELECTED_GRADE_ID(state, gradeid){
state.selectedGradeId = gradeid
},
CLEAR_SELECTED_GRADE_ID(state){
state.selectedGradeId = null
},
},
actions:{
loadStudentsForGrade (gradeId) {
return new Promise((resolve, reject) => {
axios.get('/students/'+gradeId)
.then((response)=>{
... do stuff
resolve(response)
}, response => {
reject(response)
})
})
},
}
})
and inside my component i basically have a select that loads the student list for the particular grade:
<select id="grades" name="grades" v-model="selectedGradeId" #change="loadStudentsForGrade(selectedGradeId)"
methods: {
loadStudentsForGrade(gradeId) {
this.$store.dispatch('loadStudentsForGrade', {gradeId})
.then(response => {
}, error => {
})
},
},
computed: {
selectedGradeId: {
get: function () {
return this.$store.getters.selectedGradeId;
},
set: function (gradeId) {
this.$store.commit('SET_SELECTED_GRADE_ID', gradeId);
}
},
}
when the 'loadStudentsForGrade' method is called in my component, it takes 'selectedGradeId' as a parameter, which is a computed property.
Now the problem I have is that inside my store, the action 'loadStudentsForGrade' gets an object( i guess computed?) instead of just the gradeid
object i get is printed to console:
{dispatch: ƒ, commit: ƒ, getters: {…}, state: {…}, rootGetters: {…}, …}

The first parameter of your action is the store, and the second the payload.
so you should do :
actions:{
// here: loadStudentsForGrade (store, payload) {
loadStudentsForGrade ({ commit }, { gradeId }) {
return new Promise((resolve, reject) => {
axios.get('/students/'+gradeId)
.then((response)=>{
//... do stuff
//... commit('', response);
resolve(response)
}, response => {
//... commit('', response);
reject(response)
})
})
},
}
Related page in the docs :
https://vuex.vuejs.org/en/actions.html#dispatching-actions

Related

How can I update the comments without refreshing it?

First, I'm using vuex and axios.
store: commentService.js
components:
CommentBox.vue (Top components)
CommentEnter.vue (Sub components)
This is the logic of the code I wrote.
In the store called commentService.js, there are mutations called commentUpdate.
And There are actions called postComment and getComment.
At this time, In the component called CommentBox dispatches getComment with async created().
Then, in getComment, commentUpdate is commited and executed.
CommentUpdate creates an array of comments inquired by getComment and stores them in a state called commentList.
Then I'll get a commentList with "computed".
CommentEnter, a sub-component, uses the commentList registered as compounded in the CommentBox as a prop.
The code below is commentService.js.
import axios from 'axios'
export default {
namespaced: true,
state: () => ({
comment:'',
commentList: []
}),
mutations: {
commentUpdate(state, payload) {
Object.keys(payload).forEach(key => {
state[key] = payload[key]
})
}
},
actions: {
postComment(state, payload) {
const {id} = payload
axios.post(`http://??.???.???.???:????/api/books/${id}/comments`, {
comment: this.state.comment,
starRate: this.state.starRate
}, {
headers: {
Authorization: `Bearer ` + localStorage.getItem('user-token')
}
})
.then((res) => {
console.log(res)
this.state.comment = ''
this.state.starRate = ''
)
.catch((err) => {
alert('댓글은 한 책당 한 번만 작성할 수 있습니다.')
console.log(err)
this.state.comment = ''
this.state.starRate = ''
})
},
async getComment({commit}, payload) {
const {id} = payload
axios.get(`http://??.???.???.???:????/api/books/${id}/comments`)
.then((res) => {
console.log(res)
const { comment } = res.data.commentMap
commit('commentUpdate', {
commentList: comment
})
})
.catch((err) => {
console.log(err)
commit('commentUpdate', {
commentList: {}
})
})
}
}
}
The code below is CommentBox.vue
computed: {
commentList() {
return this.$store.state.commentService.commentList
}
},
methods: {
async newComment() {
if(this.$store.state.loginService.UserInfoObj.id === '') {
alert('로그인 후 이용할 수 있습니다.')
return
}
this.$store.dispatch('commentService/postComment', {
id: this.$route.params.id,
comment: this.$store.state.comment,
starRate: this.$store.state.starRate
})
}
},
async created() {
this.$store.dispatch('commentService/getComment', {
id: this.$route.params.id
})
}
The code below is CommentEnter.vue
created() {
this.userComment = this.comment
},
props: {
comment: {
type: Object,
default: () => {}
}
},
I asked for a lot of advice.
There were many comments asking for an axios get request after the axios post request was successful.
In fact, I requested an axios get within .then() of the axios post, and the network tab confirmed that the get request occurred normally after the post request.
But it's still not seen immediately when I register a new comment.
I can only see new comments when I refresh it.
How can I make a new comment appear on the screen right away when I register it?
Can't you just call getComment when postComment is finished?
methods: {
async newComment() {
if(this.$store.state.loginService.UserInfoObj.id === '') {
alert('로그인 후 이용할 수 있습니다.')
return
}
this.$store.dispatch('commentService/postComment', {
id: this.$route.params.id,
comment: this.$store.state.comment,
starRate: this.$store.state.starRate
}).then(function() {
this.$store.dispatch('commentService/getComment', {
id: this.$route.params.id
})
})
}
},
}
Or since you're using async:
methods: {
async newComment() {
if(this.$store.state.loginService.UserInfoObj.id === '') {
alert('로그인 후 이용할 수 있습니다.')
return
}
await this.$store.dispatch('commentService/postComment', {
id: this.$route.params.id,
comment: this.$store.state.comment,
starRate: this.$store.state.starRate
})
this.$store.dispatch('commentService/getComment', {
id: this.$route.params.id
})
}
},
}

Vuejs Vuex sometimes initial state not working Error: [Vue warn]: Error in render: "TypeError: Cannot read property 'Any_Variable' of undefined"

Other pages are working fine. Only facing issue with this file. May be I am coding wrong.
Store file is included in app.js file as other pages are working I have not included it.
Here Sometimes I get undefined MDU_Number. Sometimes it work fine. I am new to vue js.
Image of error that I am receving:
This is my vue template
<div class="card-body">
<div class="form-group row">
<label class="col-sm-4 col-form-label">MDU Number</label>
<div class="col">
<input
name="MDU_Number"
:value="mduprofile.MDU_Number"
#input="updateMDUNumber"
type="text"
class="form-control"
placeholder="Enter MDU Number Ex:GJXXCHXXXX"
required
/>
</div>
</div>
</div>
<script>
import { mapGetters, mapActions } from "vuex";
export default {
data() {
return {
};
},
created() {
this.fetchForMDU();
},
destroyed() {
this.resetState();
},
computed: {
...mapGetters("MDUSingle", [
"loading",
"country",
"area",
"product",
"mduprofile",
]),
},
methods: {
...mapActions("MDUSingle", [
"resetState",
"fetchForMDU",
"storeMDU",
"setMDUNumber",
]),
submitForm() {
this.storeMDU()
.then(() => {
this.resetState();
this.$eventHub.$emit(
"create-success",
"Created",
"MDU created successfully"
);
})
.catch((error) => {
console.log(error);
});
},
updateMDUNumber(e) {
this.setMDUNumber(e.target.value);
},
},
};
</script>
This is store file name single.js and I have included it in app.js file
MDU_Number should go for null value but it goes for undefined. So I think it is not initialized properly. There are many other variables but for simplicity purpose I have included only one.
What can be the issue?
function initialState() {
return {
mduprofile: {
MDU_Number: null,
},
country: [],
area: [],
product: [],
loading: false
};
}
const getters = {
country: state => state.country,
area: state => state.area,
product: state => state.product,
loading: state => state.loading,
mduprofile: state => state.mduprofile
}
const actions = {
fetchForMDU({ commit }) {
return new Promise((resolve, reject) => {
axios.get('/get/detail/for/mdu')
.then((response) => {
let detail = response.data;
commit('setCountryAll', detail.country);
commit('setStateAll', detail.state);
commit('setProductAll', detail.product);
}).catch(error => {
reject(error);
}).finally(() => {
resolve();
});
});
},
storeMDU({ commit, state, dispatch }) {
commit('setLoading', true);
dispatch('Alert/resetState', null, { root: true });
return new Promise((resolve, reject) => {
let params = _.cloneDeep(state.mduprofile);
axios.post('/save-mdu-profile', params)
.then((response) => {
resolve();
})
.catch(error => {
commit('setLoading', false);
let message = error.response.data.message || error.message;
let errors = error.response.data.errors;
dispatch('Alert/setAlert',
{ message: message, errors: errors, color: danger },
{ root: true });
reject(error);
}).finally(() => {
commit('setLoading', false);
});
});
},
fetchData({ commit }, value) {
axios.get('/mdu/profile/' + value)
.then((response) => {
commit('setAll', response.data.mdu);
}).catch(error => {
}).finally(() => {
});
},
updateMDU({ commit, state, dispatch }) {
commit('setLoading', true);
dispatch('Alert/setAlert', null, { root: true });
return new Promise((resolve, reject) => {
let params = _.cloneDeep(state.mduprofile);
axios.put('/update-mdu-profile/' + params.MDU_Id, params)
.then((response) => {
resolve();
}).catch(error => {
let message = error.response.data.message || error.message;
let errors = error.response.data.errors;
dispatch('Alert/setAlert',
{ message: message, errors: errors, color: danger },
{ root: true });
commit('setLoading', false);
reject(error);
}).finally(() => {
commit('setLoading', false);
});
});
},
resetState({ commit }) {
commit('resetState');
},
setMDUNumber({ commit }, value) {
commit('setMDUNumber', value);
}
}
const mutations = {
resetState(state) {
state = Object.assign(state, initialState());
},
setLoading(state, loading) {
state.loading = loading;
},
setCountryAll(state, items) {
state.country = items
},
setStateAll(state, items) {
state.area = items;
},
setProductAll(state, items) {
state.product = items;
},
setAll(state, items) {
state.mduprofile = items;
},
setMDUNumber(state, value) {
state.mduprofile.MDU_Number = value;
},
setCountry(state, value) {
state.mduprofile.Country = value;
},
setState(state, value) {
state.mduprofile.State = value;
},
setProduct(state, value) {
state.mduprofile.Product = value;
}
}
export default {
namespaced: true,
state: initialState,
getters,
actions,
mutations
}
Try checking somewhere where you change this values, if you don't catch error properly you may encounter empty states.

Vue ajax request isn't updating data

I'm new to Vue but from my research this should be working. the console keeps showing users as null but when i look at the response of the request it has the users. I thought the => was supposed to update the vue instance.
...
data () {
return {
users: null,
}
},
...
methods: {
getUsers () {
this.$axios.get('/api/users')
.then(r => {
this.users = r.data
})
console.log(this.users)
},
},
...
created () {
this.getUsers()
this.users.forEach(function (u) {
...
})
}
If you want to loop through the collection of users, you have to first wait until they are actually available - you can use then callback for it:
export default {
data () {
return {
users: [],
}
},
methods: {
getUsers () {
return this.$axios.get('/api/users')
.then(r => {
this.users = r.data
})
.catch(error => console.log(error));
},
},
created () {
this.getUsers().then(() => {
this.users.forEach(function (u) {
...
})
})
}
}
Rather than converting returned collection from within vue component it would be better to return it formatted with the response - using plain php you could achieve it with array_map - here I'm using an array of User models as an example:
$users = array_map(function (User $user) {
return [
'value' => $user->id,
'name' => $user->name,
];
}, $users);
The above will return something like:
[
[
'value' => 1,
'name' => 'Jon Doe',
],
[
'value' => 2,
'name' => 'Jane Doe',
],
]
You can move your users processing to a watcher:
...
data () {
return {
users:[],
}
},
watch: {
users (users) {
if( ! this.users.length )
return;
this.users.forEach(function (u) {
...
})
},
},
...
methods: {
getUsers () {
this.$axios.get('/api/users')
.then(r => {
this.users = r.data
})
console.log(this.users)
},
},
...
created () {
this.getUsers()
}
Or if you prefer a one time processing, make it a method and call that method in the axios then():
...
methods: {
getUsers () {
this.$axios.get('/api/users')
.then(r => {
this.users = r.data
this.processUsers();
})
console.log(this.users)
},
processUsers() {
// do something with this.users
},
},

Vuex update state by using store actions

I have two functions in my store, one that gets data by calling API and one that toggles change on cell "approved". Everything working fine, except that when I toggle this change it happens in database and I get the response that it is done but It doesn't update on UI.
I am confused, what should I do after toggling change to reflect change on UI, should I call my API from .then or should I call action method responsible for getting data from server.
export default {
state: {
drivers: {
allDrivers:[],
driversError:null
},
isLoading: false,
token: localStorage.getItem('token'),
driverApproved: null,
driverNotApproved: null
},
getters: {
driversAreLoading (state) {
return state.isLoading;
},
driverError (state) {
return state.drivers.driversError;
},
getAllDrivers(state){
return state.drivers.allDrivers
}
},
mutations: {
getAllDrivers (state) {
state.isLoading=true;
state.drivers.driversError=null;
},
allDriversAvailable(state,payload){
state.isLoading=false;
state.drivers.allDrivers=payload;
},
allDriversNotAvailable(state,payload){
state.isLoading=false;
state.drivers.driversError=payload;
},
toggleDriverApproval(state){
state.isLoading = true;
},
driverApprovalCompleted(state){
state.isLoading = false;
state.driverApproved = true;
},
driverApprovalError(state){
state.isLoading = false;
state.driverError = true;
}
},
actions: {
allDrivers (context) {
context.commit("getAllDrivers")
return new Promise((res,rej)=>{
http.get('/api/admin/getAllDrivers').then(
response=>{
if (response.data.success){
let data=response.data.data;
data=data.map(function (driver) {
return {
/* response */
};
});
context.commit("allDriversAvailable",data);
res();
}else {
context.commit("allDriversNotAvailable",response.data)
rej()
}
})
.catch(error=>{
context.commit("allDriversNotAvailable",error.data)
rej()
});
});
},
toggleDriverApproval (context, payload){
return new Promise((res, rej)=>{
http.post("/api/admin/toggleDriverApproval",{
driver_id: payload
})
.then( response => {
context.commit('driverApprovalCompleted');
res();
}).catch( error =>{
context.commit('driverApprovalError');
rej()
})
})
}
}
}
and here is the code on the view, I wrote the necessary code for better clarification of the problem
export default {
name: 'Drivers',
data: () => ({
data: [],
allDrivers: [],
driversErrors: []
}),
created() {
this.$store
.dispatch('allDrivers')
.then(() => {
this.data = this.$store.getters.getAllDrivers
})
.catch(() => {
this.errors = this.$store.getters.driverError
})
},
computed: {
isLoading() {
return this.$store.getters.driversAreLoading
}
},
methods: {
verify: function(row) {
console.log(row)
this.$store.dispatch('toggleDriverApproval', row.id).then(() => {
this.data = this.$store.getters.getAllDrivers
console.log('done dis')
})
},
},
}
if I understand your issue, you want the UI displaying your data to change to the updated data after making a post request.
If you are using Vuex you will want to commit a mutation, and use a getter display the data.
I am not sure how your post request is being handled on the server but if successful typically you would send a response back to your front end with the updated data, and commit a mutation with the updated data.
Example:
Make a Post request
toggleDriverApproval (context, payload){
return new Promise((res, rej)=>{
http.post("/api/admin/toggleDriverApproval",{
driver_id: payload
})
.then( response => {
context.commit('driverApprovalCompleted', response.data);
res();
}).catch( error =>{
context.commit('driverApprovalError', error.response.data);
rej()
})
})
}
If succesful commit the mutation
.then( response => {
context.commit('driverApprovalCompleted', response.data);
res();
})
response.data being your data you want to mutate the state with.
Mutation Example:
customMutation(state, data) {
state.driverApproval = data
}
Getter Example:
driver(state) {
return state.driverApproval
}
displaying the getter in a template
<template>
<div v-if="driver">{{driver}}</div>
</template>
<script>
import {mapGetters} from 'vuex'
export default {
name: Example,
computed: {
driver() {
return this.$store.getters.driver
},
// or use mapGetters
...mapGetters(['driver'])
}
}
</script>
more examples can be found at Vuex Docs

function not defined upon requesting via axios in vue

I am trying to make an axios call and it works fine but when I call the function from the scope it returns me
loadData is undefined.
import vSelect from 'vue-select';
export default {
props : [],
data : () => {
return {
assets : [],
folders : [],
parent_id : 0,
moveParentId : null,
selectedAsset: {},
parentStack : [],
searchTerm : '',
};
},
components: {
vSelect,
},
created() {
this.loadData(this.parent_id);
this.createFolder();
},
methods : {
loadData(parentId) {
axios
.get(
'/api/assets',
{
params: {
parent_id: parentId,
},
},
)
.then((response) => {
this.parentStack.push(parentId);
this.assets = response.data;
})
.catch((error) => {
if (error.response.status === vue.$options.HTTP_STATUS.UNPROCESSABLE_ENTITY) {
}
});
},
createFolder() {
$('#create-folder-button').on('click', function (e) {
let form = $('#create-folder').find('form'),
namefield = form.find('input#name'),
name = namefield.val(),
action = '/assets',
errorelem = form.find('#create-error');
axios
.post(action, {
name: name,
type: 1,
})
.then(() => {
$('#create-folder').modal('hide');
loadData(this.parent_id); //ERROR OCCURS HERE.
}, function (error) {
if (error.response != null) {
if (error.response.status == vue.$options.HTTP_STATUS.UNPROCESSABLE_ENTITY) {
errorelem.html(error.response.status).show();
}
}
});
});
}
this is my code.