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/
Related
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>
Not sure if this is the place to change things, but I have changed some things due to your comments, I stil cant see the pictures, but here is an update of the code:
JS app:
import axios from 'axios';
export default {
name: 'home',
components: {
ImageCard
},
data() {
return {
images: []
}
},
methods: {
fetchImages = () => {
axios
.get("https://foodish-api.herokuapp.com/api/images/pizza")
.then(res => {
console.log(res);
this.setState({ images: res.data.message });
})
.catch(err => console.log(err));
this.images = fetchImages()
});
}
Index.cshtml code here:
<div id="app">
<div class="home">
<li v-for="image in images" :key="image.id">
<img :src="image.url" :alt="image.alt" />
</li>
</div>
Obviously something wrong here but i cant seem to get it right since I cant see the pictures, what is still wrong here? Also, when your refer to something I should do different, please just point me in the right direction of the code :D
you did wrong the following:
create a method fetchImages and never call it.
this.setState this undifined function.
this.images = fetchImages() will lead you to infinite loop because this is a recursion function
in your html use :src="image.url" to show the image but you get the data as string not object and you must use :src="image"
you can check the solution in this codesandbox project
https://codesandbox.io/s/busy-ellis-rcifm?file=/src/App.vue
<template>
<div id="app">
<li v-for="image in images" :key="image.id">
<img :src="image" :alt="image.alt" />
</li>
</div>
</template>
<script>
import axios from "axios";
export default {
name: "App",
data() {
return {
images: [],
};
},
mounted() {
axios
.get("https://foodish-api.herokuapp.com/api/images/pizza")
.then((res) => {
this.images = res.data;
})
.catch((err) => console.log(err));
},
};
</script>
Firstly,when you call fetchImages(),you need to set this.images=fetchImages(),so that the data of images will be set.And if you want to display pictures,you can do like this:
<li v-for="image in images" :key="image.id">
<img :src="image.url" :alt="image.alt"/>
</li>
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 made a list of items which are taken on the link. Near each element there is a button to delete when clicked on which the element should be removed from the site and api. The fact is that when I click on the delete button, everything is normal from the api, and from the site, if you delete the elements from the bottom up, it is normal, and if from top to bottom, it does not work correctly. I understand that the matter is in the splice parameters, but I do not know how to fix it.
Screenshot of list
<template>
<div id="app">
<ul>
<li v-for="(post, id) of posts">
<p>{{ post.title }}</p>
<p>{{ post.body }}</p>
<button #click="deleteData(post.id)">Delete</button>
</li>
</ul>
</div>
</template>
<script>
import axios from 'axios';
export default {
name: 'app',
data () {
return{
posts: [],
}
},
created(){
axios.get('http://jsonplaceholder.typicode.com/posts').then(response => {
this.posts = response.data
})
},
methods: {
deleteData(id) {
axios.delete('http://jsonplaceholder.typicode.com/posts/' + id)
.then(response => {
console.log('delete')
this.posts.splice(id-1, 1)
})
.catch(function(error) {
console.log(error)
})
},
}
}
</script>
This id here is actually the index, not really the post.id, whereas splice() takes a start index, see the signature here:
<li v-for="(post, id) of posts">
<!----------------^^--- This is essentially posts[index] -->
So try doing the following instead:
<template>
<div id="app">
<ul>
<li v-for="(post, index) of posts">
<p>{{ post.title }}</p>
<p>{{ post.body }}</p>
<button #click="deleteData(index, post.id)">Delete</button>
</li>
</ul>
</div>
</template>
methods: {
deleteData(index, id) {
axios
.delete('http://jsonplaceholder.typicode.com/posts/' + id)
.then(response => {
this.posts.splice(index, 1);
})
.catch(function (error) {
console.log(error)
})
},
}