Why is my false conditional element fickering while route is loading? - javascript

Background: I have a page that displays a different div depending on Axios response. If the Axios Get request brings back response that does not populate data array myExpense[], it shows the div with the alert-warning class. Other wise if the response does populate the array it shows the div with the alert-succes class.
Here is the code:
<template>
<div class="profilePage">
<div class="container">
<div class="row">
<div class="col" v-if="Array.isArray(myExpense)
&& myExpense == 0"><!--Warning div-->
<p class="alert alert-warning">You do not have a budget at the moment</p>
<router-link to="/budgetform" tag="button" class="btn btn-primary mt-5">Create Budget</router-link>
</div>
<div v-else class="col-md-12 alert alert-success"><!--Success div-->
<p class="yourBalance">
Your monthly balance
<br />
<span>${{myExpense[0].earnings}}</span>
</p>
<router-link to="/mybudget" tag="button" class="btn btn-primary mt-5">My budget</router-link>
</div>
</div>
<div class="row">
<div class="col-md-12">
Logout
</div>
</div>
</div>
</div>
</template>
<script>
import axios from "axios";
export default {
name: "userProfile",
data() {
return {
myExpense: [],//This array to be populated by axios response
};
},
methods: {},
created() {
axios
.get("http://localhost:3000/budget", {
headers: { "Content-Type": "application/json" },
withCredentials: true
})
.then(res => {
if (res.data.name == undefined) {
this.$router.push("/");
}
this.profile = res.data;
this.myExpense = res.data.budget;
});
}
};
</script>
Problem:
Whenever this page is rendered, the false div flickers before displaying the right div based on the condition. Also, sometimes it shows white space as well.
I tried adding v-cloak but that doesn't seem to be the problem.
Thanks in advance for the help

I was able to find out the problem. The get request was not retrieving the data as fast as it took to render the page. So I had to use beforeRouteEnter to the retrieve the data before the component renders
Like so:
beforeRouteEnter(to, from, next) {
axios
.get("http://localhost:3000/budget", {
headers: { "Content-Type": "application/json" },
withCredentials: true
})
.then(res => {
next(vm => {
vm.userName = res.data.name;
vm.myExpenses = res.data.budget[0].expenses;
vm.earnings = res.data.budget[0].earnings;
});
})
.catch(err => {
next(vm => {
vm.err = err;
});
});
}

Related

Vue - Get id of particular clicked post

Basically my goal is getting the number of click for each post.
Until now, i only just successfully get the number per clicks on console :
But i need to know which post was clicked, For distinct that, i want to display the id of post, so i supposed each post have some: _id
That is my post content from my DB :
My code :
<template>
<div w="3" v-for="(post, post_id) in posts" :key="post_id">
<div class="card-view" #click="getStat(post_id)">
<div class="container">
<div class="tag_name blue">{{ post.title }}</div>
<div class="company">{{ post.body }}</div>
<div class="c_logo">
<img :src="`${post.image}`"/>
</div>
</div>
</div>
</div>
</template>
<script>
import axios from 'axios'
export default {
name: "Home",
components: {
modal,
},
data: () => ({
posts: [],
}),
methods : {
getStat : function() {
let increment = this.counter += 1
console.log(increment)
let result = axios.post("http://localhost:3000/allPostClicked", {
numberOfClick: increment,
postID: this.post_id
})
console.log(result)
}
},
},
</script>
...and when i clicked on some post, i got this error on my console :
[[Prototype]]
:
Promise
[[PromiseState]]
:
"rejected"
[[PromiseResult]]
:
Error: Request failed with status code 404 at createError (webpack-internal:///./node_modules/axios/lib/core/createError.js:16:15) at settle (webpack-internal:///./node_modules/axios/lib/core/settle.js:17:12) at XMLHttpRequest.onloadend (webpack-internal:///./node_modules/axios/lib/adapters/xhr.js:54:7)
config
:
{url: 'http://localhost:3000/allPostClicked', method: 'post', data: '{"numberOfClick":null}', headers: {…}, transformRequest: Array(1), …}
isAxiosError
:
true
request
...
If I understood you correctly take a look at following snippet
const app = Vue.createApp({
data: () => ({
posts: [],
}),
async mounted() {
await this.getPosts()
this.posts = this.posts.map(p => {
return {...p, numberOfClick: 0}
})
},
methods : {
async getPosts() {
await fetch('https://jsonplaceholder.typicode.com/posts')
.then(response => response.json())
.then(json => this.posts = json)
},
getStat(id) {
const post = this.posts.find(c => c.id === id)
post.numberOfClick++
},
},
})
app.mount('#demo')
<script src="https://unpkg.com/vue#3/dist/vue.global.prod.js"></script>
<div id="demo">
<div w="3" v-for="(post, i) in posts" :key="i">
<div class="card-view" #click="getStat(post.id)">
<div class="container">
<h5 class="tag_name blue">{{ post.title }}</h5>
<div class="company">{{ post.body }}</div>
<h3>{{ post.numberOfClick }}</h3>
</div>
</div>
</div>
</div>

Data from API doesn't show up in website but shows no error vuejs + axios

I'm learning vue js right now, and trying to get API data from this site https://reqres.in/ with axios. I want to take the data like email, name and put it into a card. It shows no error because the card is looping, but the data itself, like email and name, doesn't show up. How do I fix this?
here's is my script
data() {
return {
users: [],
};
},
methods: {
setUsers(data) {
this.users = data;
},
},
mounted() {
axios
.get("https://reqres.in/api/users")
.then((response) => this.setUsers(response.data))
.catch((error) => console.log("Gagal : ", error))
},
my card
<div class="row mb-3">
<div class="col md-2 mt-4" v-for="user in users" :key="user.id">
<card :user="user"/>
</div>
</div>
and my card components
<template>
<div>
<h2>Card API {{user.email}}</h2>
</div>
</template>
<script>
export default {
name: 'card',
props: ['user']
};
</script>
the output on my site is just 'Card API' looping for 6 times because the total data is 6 but not the email. Please help, thank you
The response.data you get is an object you fetched from the API. You need to access the "data" property of this object:
.then((response) => this.setUsers(response.data.data))

Vue computed property do not send data to template

I have a Login Page on which the user has to authorize and it is working.
Then the user is being redirected to the next page called Dashboard and I want to get his user profile details from the different endpoint, using Vuex.
I can see in the console, that data is retrieved immediately after the page is loaded, but it's not displayed on the page, I need to refresh the page to load the data. Can someone help me to figure out how to get rid of the page reload and put the data there automatically?
First, under created() I am using dispatch to get the data, and then in the computed present it.
Here is my code first Dashbaord.vue and user.module.js:
import HeaderBar from "#/components/header/HeaderBar.vue";
export default {
name: "Dashboard",
components: { HeaderBar },
created() {
this.$store.dispatch("user_account/getUserDetails");
console.log("DASHBOARD: Created");
console.log(this.$store.status);
},
computed: {
currentUser() {
console.log("Computed");
console.log(this.$store.state);
return this.$store.state.user_account;
},
},
};
.dashboard {
h4 {
line-height: 18px;
}
}
<template>
<div>
<main role="main">
<div
class="d-flex justify-content-between flex-wrap flex-md-nowrap align-items-center pt-3 pb-2 mb-3"
>
<h1 class="h1">Hi, {{ currentUser.first_name }}</h1>
<div class="btn-toolbar mb-2 mb-md-0">
<div class="btn-group mr-2">
Search will be here added
</div>
</div>
</div>
</main>
<div class="mt-4 mb-5">
<HeaderBar />
</div>
<main role="main">
<div class="row mb-2">
</div>
</main>
</div>
</template>
import UserService from "../services/user.service";
const user = JSON.parse(localStorage.getItem("user"));
console.log("USER MODULE: ")
console.log(user)
const initialState = user
? user
: null;
console.log(initialState)
export const user_account = {
namespaced: true,
state: initialState,
actions: {
async getUserDetails({commit}) {
return UserService.getUserDetails().then(
(user) => {
commit("getUserDetailsSuccess", user);
return Promise.resolve(user);
},
(error) => {
commit("getUserDetailsFailure");
return Promise.reject(error);
}
);
}
},
mutations: {
getUserDetailsSuccess(state, user) {
state.user = user;
},
getUserDetailsFailure(state) {
state.user = null;
}
}
};
user_account/getUserDetailsSuccess sets state.user, but your computed prop does not return .user.
It should look like this:
export default {
created() {
this.$store.dispatch('user_account/getUserDetails')
},
computed: {
currentUser() {
// return this.$store.state.user_account ❌
return this.$store.state.user_account.user
},
},
}
demo

Vue data function returns values but vue ignores them

Can anyone please tell me why vue is ignoring my data function return values? text, userId, and videoId. Sometimes it doesn't ignore them and a lot of times it does out of nowhere and I'm not sure why. Here is my code. What I get in chrome vue extension is data: $routes but it should be data: text: '', videoId: 213, userId: null $routes. And sometimes it does appear and I have no idea why it does and doesn't at times.
<template>
<div class="selected">
<h2 class="selected__title">{{video.title}}</h2>
<video class="selected__video" :src=video.video controls :poster=video.thumb></video>
<div style="width: 70%;">
<div class="selected__details">
<h3 class="selected__details__views">300 views</h3>
<div class="selected__thumbs">
<div class="selected__like">👍 47</div>
<div class="selected__dislike">👎 3</div>
</div>
</div>
<form class="selected__commentbox">
<label for="comments" class="selected__commentbox__label">Comments</label>
<textarea v-model="text" class="selected__commentbox__textarea" rows="4" id="comments" placeholder="Type a sweet comment..."></textarea>
<button #click="handleSubmit" class="selected__commentBtn">add comment</button>
</form>
<div v-bind:key="comment._id" v-for="comment in video.comments" class="selected__comments">
<Comment v-bind:comment="comment"/>
</div>
</div>
</div>
</template>
<script>
import Comment from './Comment.component.vue';
import axios from 'axios';
export default {
name: 'SelectedVideo',
data() {
return {
text: null,
videoId: this.video._id,
userId: this.user._id
}
},
props: ["video", "user"],
components: {
Comment
},
methods: {
handleSubmit(event) {
event.preventDefault();
this.createComment(this.text, this.videoId, this.userId);
this.text = '';
},
updateComments() {
this.$store.state.newComment = true;
},
async createComment(comment, video, user) {
try{
const res = await axios({
method: 'POST',
url: 'http://localhost:8000/api/v1/comments/',
data: {
comment,
video,
user
}
});
if (res.data.status === 'success') {
// console.log(res);
this.updateComments();
location.reload(true);
}
} catch(err) {
console.log(err.response.data.message);
}
}
}
}
</script>
I get errors such as: Property or method "videoId" is not defined on the instance but referenced during render. Make sure that this property is reactive, either in the data option, or for class-based components, by initializing the property.

vuejs displaying API data using attribute binding

I have a simple app where a user selects a Person and vue makes an api call for that users posts.Each of these posts in turn have their own comments.This is all from https://jsonplaceholder.typicode.com/
The comment section is always empty.
The codepen is here
My html
<script src="https://unpkg.com/axios/dist/axios.min.js"></script>
<div id='app'>
<div v-if='isError'>
There was an error
</div>
<div v-else-if='isLoading'>
Loading
</div>
<div v-else>
<select v-model="selectedUser">
<option v-for="person in info" v-bind:value="person"> {{person.name}}</option>
</select>
</div>
<div class="posts">
<div v-if="isLoadingPosts">
Loading...
</div>
<div v-else>
<ul>
<li v-for="post in postData">
<p>
{{ post.body }}
</p>
<button v-bind:id='post.id' v-on:click='getComments'>
View Comments
</button>
</li>
</ul>
</div>
</div>
<div class="comments">
<p>
{{ commentData }}
</p>
</div>
</div>
JS logic
var app = new Vue({
el: '#app',
data: {
info : null,
isLoading : true,
isError : false,
selectedUser : '',
postData : null,
isLoadingPosts : true,
commentData : null,
},
watch : {
selectedUser : function () {
axios
.get('https://jsonplaceholder.typicode.com/posts?userId=' + this.selectedUser.id)
.then(response => (this.postData =response.data))
.catch(error=> {console.log(error)})
.finally(() => this.isLoadingPosts = false)
}
},
methods : {
getComments : function (){
axios
.get('https://jsonplaceholder.typicode.com/posts/' + this.id + '/comments')
.then(response => (this.commentData =response.data))
}
},
mounted () {
axios
.get('https://jsonplaceholder.typicode.com/users')
.then(response => (this.info = response.data))
.catch(error => {console.log(error);this.isError = true})
.finally(() => this.isLoading = false)
}
})
Everything works except the comments part where it always returns an empty object.I also feel that my code is repetitive,any corrections would be appreciated.
So you have a couple issues with this method:
getComments : function (){
axios
.get('https://jsonplaceholder.typicode.com/posts/' + this.id + '/comments')
.then(response => (this.commentData =response.data))
}
}
First, this.id in there will be looking for an id prop on the component itself, not the id you're trying to bind in your button.
Try changing the button code to this:
<button v-on:click='getComments(post.id)'>View Comments</button>
And then the method to:
getComments : function (id){
axios
.get('https://jsonplaceholder.typicode.com/posts/' + id + '/comments')
.then(response => (this.commentData =response.data))
}
}
Also, you might want to add a .catch() handler like you id for your other axios calls.

Categories

Resources