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>
Related
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;
});
});
}
I display data using Wordpress API in nuxt js. I try to display data in category wise example where ('post.category ', '=', 'categoryName ') what is the syntax in vuejs/nuxtjs.
Is it even possible?
script:
import axios from 'axios'
export default {
data() {
return {
posts: []
}
},
asyncData() {
return axios.get('http://localhost/wordpress/wp-json/wp/v2/posts')
.then(res => {
return {
posts: res.data
}
})
}
}
template
<div class="col-lg-4" v-for="post in posts" :key="post.id">
<div class="news-post image-post">
<img :src="post.fi_300x180">
<div class="hover-post text-center">
<a class="category-link" href="#">Travel</a>
<h2>{{post.slug}}</h2>
<ul class="post-tags">
<li>by Stan Enemy</li>
<li>3 days ago</li>
</ul>
</div>
</div>
</div>
If i've understood your question right, you're wanting to populate the posts array with the response from your axios get request?
If so, then you could do this as follows:
<template>
<div>
<p v-if="loading">Loading posts...</p>
<div v-for="post in posts" :key="post.id">
<h3>{{ post.title }}</h3>
<p>{{ post.snippet }}</h3>
</div>
</div>
</template>
<script>
import axios from 'axios'
export default {
data() {
return {
posts: [],
loading: false
}
},
created() {
this.fetchData()
}
methods: {
fetchData() {
this.loading = true
axios
.get('endpoint')
.then(res => {
this.posts = res.data.posts
this.loading = false
})
.catch(error => {
//handle error
})
}
}
}
</script>
I've recreated this using a setTimeout function to imitate a call to the api.
https://jsfiddle.net/5b9ofqgh/
I had a page on which there was a header with an input that was a search engine, a list of posts, and pagination. I decided to move the header from this file to a separate component in a separate vue file. After I did this, the search for posts by title stopped working, and I can’t add a post now either. I think that I need to import my posts into a new file for my newly created component but how to do it.
My code when it worked(before my changes)
My code is not working after the changes:
The file in which my posts situated:
<template>
<div class="app">
<ul>
<li v-for="(post, index) in paginatedData" class="post" :key="index">
<router-link :to="{ name: 'detail', params: {id: post.id, title: post.title, body: post.body} }">
<img src="src/assets/nature.jpg">
<p class="boldText"> {{ post.title }}</p>
</router-link>
<p> {{ post.body }}</p>
</li>
</ul>
<div class="allpagination">
<button type="button" #click="page -=1" v-if="page > 0" class="prev"><<</button>
<div class="pagin">
<button class="item"
v-for="n in evenPosts"
:key="n.id"
v-bind:class="{'selected': current === n.id}"
#click="page=n-1">{{ n }} </button>
</div>
<button type="button" #click="page +=1" class="next" v-if="page < evenPosts-1">>></button>
</div>
</div>
</template>
<script>
import axios from 'axios';
export default {
name: 'Pagination',
data () {
return {
search: '',
current: null,
page: 0,
posts: [],
createTitle: '',
createBody: '',
visiblePostID: '',
}
},
watch: {
counter: function(newValue, oldValue) {
this.getData()
}
},
created(){
this.getData()
},
computed: {
evenPosts: function(posts){
return Math.ceil(this.posts.length/6);
},
paginatedData() {
const start = this.page * 6;
const end = start + 6;
return this.posts.filter((post) => {
return post.title.match(this.search);
}).slice(start, end);
},
},
methods: {
getData() {
axios.get(`https://jsonplaceholder.typicode.com/posts`).then(response => {
this.posts = response.data
})
},
}
}
</script>
Header vue:
AddPost
<script>
import axios from 'axios';
export default {
name: 'Pagination',
data () {
return {
search: '',
current: null,
posts: [],
createTitle: '',
createBody: '',
}
},
created(){
this.getData()
},
methods: {
getData() {
axios.get(`https://jsonplaceholder.typicode.com/posts`).then(response => {
this.posts = response.data
})
},
addPost() {
axios.post('http://jsonplaceholder.typicode.com/posts/', {
title: this.createTitle,
body: this.createBody
}).then((response) => {
this.posts.unshift(response.data)
})
},
}
}
</script>
App.vue:
<template>
<div id="app">
<header-self></header-self>
<router-view></router-view>
</div>
</template>
<script>
export default {
components: {
name: 'app',
}
}
</script>
You have a computed property paginatedData in your "posts" component that relies a variable this.search:
paginatedData () {
const start = this.page * 6;
const end = start + 6;
return this.posts.filter((post) => {
return post.title.match(this.search);
}).slice(start, end);
},
but this.search value is not updated in that component because you moved the search input that populates that value into the header component.
What you need to do now is make sure that the updated search value is passed into your "posts" component so that the paginatedData computed property detects the change and computes the new paginatedData value.
You're now encountering the need to pass values between components that may not have a parent/child relationship.
In your scenario, I would look at handling this need with some Simple State Management as described in the Vue docs.
Depending on the scale of you app it may be worth implementing Vuex for state management.
I have something like /url/{category}.
This is the code to fetch some of these on the main page:
export default {
data() {
return {
topnews:[],
newsfive:[],
categories: {
tshirts:'',
shirts:'',
shoes:'',
useful:'',
}
}
},
methods() {
async getAll(){
axios.all([
axios.get(`/topnews`),
axios.get(`/news`),
axios.get(`/tshirts`),
axios.get(`/shirts`),
axios.get(`/shoes`),
axios.get(`/useful`)])
.then(axios.spread((topnews, news, tshirts, shirts, shoes, useful) => {
news.data.length = 5;
tshirts.data.length = 5
shirts.data.length = 5
shoes.data.length = 5
useful.data.length = 5
// How to limit these appropriately?
this.newsfive = news.data;
this.topnews = topnews.data;
this.categories = {
tshirts: tshirts.data,
shirts: shirts.data,
shoes: shoes.data,
useful: useful.data,
}
})).catch(error => console.log(error))
}
}
created() {
this.getAll()
}
}
This works, but If I change the route to /tshirts and use browser back to the main page, I get:
typeerror content read-only property
Also is it possible to combine this into a single array instead of creating 7 different divs like:
<div v-for="tshirts,key in categories.tshirts" :key="categories.tshirts.slug">
<img :src="tshirts.thumb" class="img-responsive" width=100%/>
<p>{{tshirts.title}}</p>
</div>
Instead have something like a filtered computed axios response and then just use a single div?
<div v-for="item,key in categories(tshirts)" :key="categories(item.slug)">
How can I limit the axios array response size?
Create Category.vue to render only category content
<template>
<div v-for="(item, key) in category" :key="item.slug">
<img :src="item.thumb" class="img-responsive" width=100% />
<p>{{ item.title }}</p>
</div>
</template>
<script>
export default {
data() {
return {
category: { }
}
},
methods() {
getCategory() {
axios.get(`/${this.$route.params.category}`)
.then((response) => {
this.category = response.data.slice(0, 5);
}).catch(error => console.log(error));
}
}
created() {
this.getCategory()
}
}
</script>
And in App.vue add router-link to all categories
<template>
<nav>
<router-link to="{ name: 'category', params: {category: 'tshirts'} }">T-Shirts</router-link>
<router-link to="{ name: 'category', params: {category: 'shirts'} }">Shirts</router-link>
<!-- and other -->
</nav>
<main>
<router-view></router-view>
</main
</template>
Don't forger about vue-router
import Category from "./Category.vue"
routes = [
{
name: "category",
path: "/:categoryId",
component: Category
}
]
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.