How can I update the comments without refreshing it? - vue.js

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
})
}
},
}

Related

Nuxt js Router Push Not Working After Delete

I've created a simple CRUD with Nuxt. Data is provided by Lumen. I got a problem with the DELETE, data is deleted but Nuxt does not redirect to the other page.
Here is my script:
<script>
export default {
name: 'EmployeePage',
data() {
return {
fields: ['name','email','image','address'],
emplyees:[],
}
},
mounted() {
this.$axios.get('/employee').then(response => {
this.pegawais = response.data.data
}).catch(error => {
console.log(error.response.data)
})
},
methods: {
async delete(id) {
await this.$axios.delete(`/employee/${id}`).then(response => {
this.$router.push({ name: 'employee' }) <-----this redirect not working
})
}
}
}
</script>
I want Nuxt to redirect to the employee page that display all the data after the deletion.
You should not mix async/await and .then. Use the first approach, that way you will not have the .then callback hell and it will be cleaner overall.
Like this
<script>
export default {
name: 'EmployeePage',
data() {
return {
fields: ['name', 'email', 'image', 'address'],
emplyees: [],
}
},
async mounted() {
try {
const response = await this.$axios.get('/employee')
this.pegawais = response.data.data
} catch (error) {
console.log(error.response.data)
}
},
methods: {
async delete(id) {
await this.$axios.delete(`/employee/${id}`)
await this.$router.push({ name: 'employee' })
},
},
}
</script>
await this.$router.push does not require an await but it's a Promise too, so I'm writing it like that in case you need to call something else afterwards.
this.$axios.$get('/employee') can also be used if you want to remove a .data aka this.pegawais = response.data as shown here.

Vuex is not mutating the state

I am trying to switch authenticated from false to true, a property in the state, It's not working.
My codes from store.js
state() {
return{
authenticated : false,
user : {}
}
},
getters : {
authenticated(state){
return state.authenticated
}
},
mutations : {
set_authenticated(state, value){
return state.authenticated = value
}
},
My updated code from login.vue (script)
data() {
return {
allerrors : [],
success : false,
data: {
email : "",
password : ""
}
}
},
methods : {
login: function() {
this.$store
.dispatch("login", this.data)
.then(response => {
this.allerrors = [],
this.success = true,
this.data = {}
alert(response.data)
})
.catch((error) => {
this.allerrors = error.response.data.error
this.success = false
alert(allerrors)
})
},
My updated action is :
async login({ commit }, data) {
await axios.post('login', data)
.then(response => {
commit('set_authenticated',true);
})
.catch((error) => {
this.allerrors = error.response.data.error
this.success = false
})
}
There are a few problems here:
First, if that is the full code for your store.js file, then you are missing the call to createStore() (for Vue 3) or new Vuex.Store() (for Vue 2)
import { createStore } from 'vuex'
// Create a new store instance.
const store = createStore({
state () {
return {
count: 0
}
},
mutations: {
increment (state) {
state.count++
}
}
})
Source
The second problem is that you shouldn't be committing mutations from your Single File Components. The typical flow is:
Components dispatch actions
Actions commit mutations
Mutations update state
You're trying to commit a mutation directly from the component.
You need to add an action to your store.js
async login({ commit }, userData) {
await axios.post('login', userData)
.then(response => {
commit('set_authenticated',true);
})
.catch((error) => {
this.allerrors = error.response.data.error
this.success = false
})
}
Mutation:
mutations : {
set_authenticated(state, value){
state.authenticated = value
}
},
Then your Login.vue would change to something like:
methods: {
login: function() {
this.$store
.dispatch("login", { userData })
.then(() => )) // whatever you want to do here.
.catch(err => console.error(err));
}
}
mutations shouldn't have a return statement. it should be like this
mutations : {
set_authenticated(state, value){
state.authenticated = value
}
},

How to fetch data in Vue 3?

I don't know how to fetch data with Vue 3? I created one action and with this action I am calling endpoint (https://api.openbrewerydb.org/breweries/5494). I didn't get response data.
Endpoint:
import { createStore } from 'vuex'
export default createStore({
state: {
},
mutations: {
},
actions: {
async getData() {
await fetch('https://api.openbrewerydb.org/breweries/5494', {
method: 'get',
headers: { 'Content-type': 'application/json' },
}).then((response) => {
if (!response.ok) {
throw Error(response.statusText);
}
console.log('response: ', response)
}).catch((error) => {
console.log('Looks like there was a problem: \n', error);
});
}
},
modules: {
}
})
Vue component:
<template>
<div #click="loadData">Load Data</div>
</template>
<script>
import { useStore } from 'vuex'
export default {
name: 'HelloWorld',
props: {
msg: String
},
setup () {
const store = useStore()
const loadData = () => {
store.dispatch('getData')
}
return { loadData }
}
}
</script>
As a response I didn't get anything but I should get:
{"id":5494,"name":"MadTree Brewing","brewery_type":"regional","street":"3301 Madison Rd","address_2":null,"address_3":null,"city":"Cincinnati","state":"Ohio","county_province":null,"postal_code":"45209-1132","country":"United States","longitude":"-84.4239715","latitude":"39.1563725","phone":"5138368733","website_url":"http://www.madtreebrewing.com","updated_at":"2018-08-24T15:44:22.281Z","created_at":"2018-07-24T01:34:01.620Z"}
You need to make the data to json
.then(res=>res.json())
this will do the trick for you.
const getData = () => {
fetch('https://api.openbrewerydb.org/breweries/5494', {
headers: { 'Content-type': 'application/json' },
}).then(res=>res.json()).then((response) => {
console.log({ response })
}).catch((error) => {
console.log('Looks like there was a problem: \n', error);
});
}
getData();
If the response fails, it will surely get you to catch.
This answer Should be the accepted answer.
If readers landed here while working through the introductory examples on the Vue.js website, Adarsh's code can be adapted thusly (for Vue.js 3):
<div id="beer">
{{ message }}
</div>
const Breweries = {
data() {
return {
message: ""
}},
mounted() {
fetch('https://api.openbrewerydb.org/breweries/', {
headers: { 'Content-type': 'application/json' },
}).then(res=>res.json()).then((response) => {
this.message = response;
}).catch( (error) => {
this.message = error;
});
}
}
Vue.createApp(Breweries).mount('#beer')
First you must install a package like axios
Then create an object from axios and call the API
import axios from "axios";
export default {
setup() {
function getUsers() {
axios.get("https://jsonplaceholder.typicode.com/users")
.then(function (response) {
// handle success
console.log(response.data);
})
.catch(function (error) {
// handle error
console.log(error);
});
getUsers();
}
return { getUsers };
},
};

Vue.js with Axios use data from other method

I have a external api which returns a json of a user with some attributes like username. I want to use this username in my vue methods as a url parameter and defined the function getUser(). My problem is that the parameter keeps undefined
Here is my code
<script>
import Axios from 'axios-observable'
export default {
data () {
return {
appointments: {},
event_counter: 0,
user: ''
},
methods: {
getUser: function () {
Axios
.get('http://127.0.0.1:5000/users/get_user')
.subscribe(response => { this.user = response.data.username })
},
getAppointments: function () {
Axios
.get('http://127.0.0.1:5000/appointments/get_appointments?user=' + this.user)
.subscribe(response => { this.appointments = response.data })
},
fetchData: function () {
setInterval(() => {
this.getAppointments()
}, 150000)
}
},
mounted () {
//this.user = this.getUser()
this.getUser()
this.fetchData()
},
created () {
//this.user = this.getUser()
this.getUser()
this.getAppointments()
}
}
</script>
I tried some variants with return response.data or data: this.getUser() etc. Obtaining the user in template with {{ user }} works fine but isn't helpful. I don't have any syntax or runtime error from vue/electron-vue
Any idea?
Finally got a solution!
<script>
import Axios from 'axios'
export default {
data () {
return {
appointments: {},
event_counter: 0,
user: 'test'
}
},
methods: {
getUser: function () {
return Axios
.get('http://127.0.0.1:5000/users/get_user')
.then(response => {
this.user = response.data.username
return this.user
})
},
getAppointments: function () {
this.getUser()
.then(data => {
let url = 'http://127.0.0.1:5000/appointments/get_appointments?user=' + data
Axios
.get(url)
.then(response => { this.appointments = response.data })
})
},
fetchData: function () {
setInterval(() => {
this.getAppointments()
}, 150000)
}
},
mounted () {
this.fetchData()
},
created () {
this.getAppointments()
}
}
</script>
The solution was to change the call of the getUser() and retrieve the date in the arrow function block .then(data =>).
The answer of #loan in this Issue give me the hint: How to set variable outside axios get.
Thanks a lot to all.
<script>
import Axios from 'axios-observable'
export default {
data () {
return {
appointments: {},
event_counter: 0,
user: ''
},
computed: {
updatedUrl: {
return `http://127.0.0.1:5000/appointments/get_appointments?user=${this.user}`
}
},
methods: {
forceGetUsername() {
return this.user
},
getUser: function () {
Axios
.get('http://127.0.0.1:5000/users/get_user')
.subscribe(response => { this.user = response.data.username })
},
getAppointments: function () {
console.log(updatedUrl)
Axios
.get(updatedUrl)
.subscribe(response => { this.appointments = response.data })
},
// Below can remain the same
}
</script>
So it seems the url is being cached and not updated once created. So I added new function to ensure the latest value is being returned. Not very ideal.
Added the URL to computed property. If this doesn't work then I am lost as well :(

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