I have cloned this awesome shopping cart repo from https://github.com/vueschool/learn-vuex, it works good but doesn't handle data for my use case. For anyone who has used this repo, how do i extend it by getting products from database or Api?
Shop.js
const _products = [
{"id": 1, "title": "iPad 4 Mini", "price": 500.01, "inventory": 2},
{"id": 2, "title": "H&M T-Shirt White", "price": 10.99,
"inventory": 10},
{"id": 3, "title": "Charli XCX - Sucker CD", "price": 19.99,
"inventory": 5}
]
export default {
getProducts (cb) {
setTimeout(() => cb(_products), 100)
},
buyProducts (products, cb, errorCb) {
setTimeout(() => {
// simulate random checkout failure.
(Math.random() > 0.5 ||
navigator.userAgent.indexOf('PhantomJS') > -1)
? cb()
: errorCb()
}, 100)
}
}
Shop gets called via vuex actions
actions: {
fetchProducts({commit}) {
return new Promise((resolve, reject) => {
// make the call
// call setProducts mutation
shop.getProducts(products => {
commit('setProducts', products)
resolve()
})
})
}
You can use axios to make a call to the server and get products like following
export default new Vuex.Store({
state: {
products: {},
},
actions: {
getProducts({commit},data) {
axios.get(`api/product?page=`+ data.page + '&orderBy='+ data.orderBy).then((response) => {
commit('updateProducts', response.data);
})
},
mutations: {
updateProducts (state, products) {
state.products = products
}
}
});
Related
I'm working on an app in which if a category is clicked it goes to another route and list the product under that category.
This is my html template category id routes :
<div>
<p>{{category.type}}</p>
<div
v-for="product in products(category._id)"
:key="product._id"
>
{{product.title}}
</div>
</div>
My script tag :
<script>
import axios from "axios";
export default {
name: "Product",
components: {},
data() {
return {
categoryID: null,
category: [],
products: [],
show: null
};
},
mounted() {
axios
.get(`http://localhost:5000/api/categories/${this.$route.params.id}`, {})
.then(response => {
console.log(response);
this.category = response.data.category;
})
.catch(error => {
console.log(error);
error;
});
axios
.get(`http://localhost:5000/api/products`, {})
.then(response => {
console.log(response);
this.product = response.data.product;
})
.catch(error => {
error;
});
},
};
</script>
Response I get in my console, the list of categories :
{
"success": true,
"category": {
"_id": "6220db08e861f3dbbaf21e39",
"products": [],
"type": "3 bedroom",
"__v": 0
}
}
This is my list of products :
{
"products": [
{
"_id": "6256711a0e42d6c5ab370e9d",
"category": {
"_id": "6220db08e861f3dbbaf21e39",
"products": [],
"type": "3 bedroom",
"__v": 0
},
"title": "galaxy s22",
"price": 200,
"stockQuantity": 1,
"__v": 0,
"id": "6256711a0e42d6c5ab370e9d"
},
]
}
my category api
router.get(`/categories/:id`, async (req, res) => {
try {
let category = await Category.findOne({
_id: req.params.id
})
res.json({
success: true,
category: category
});
} catch (err) {
res.status(500).json({
success: false,
message: err.message
});
}
});
How can I get the list of products under a specific category ? I get the {{ category.type }}
My suggestion is to filtered out the products in the script and then bind that in the template as you are getting only one category object from an API.
Demo :
new Vue({
el: '#app',
data: {
// This is a mock data just for a demo (actual will come from API)
category: {
"success": true,
"category": {
"_id": "6220db08e861f3dbbaf21e39",
"products": [],
"type": "3 bedroom",
"__v": 0
}
},
// This is a mock data just for a demo (actual will come from API)
products: [
{
"category": {
"_id": "6220db08e861f3dbbaf21e39"
},
"title": "galaxy s22"
}, {
"category": {
"_id": "6220db08e861f3dbbaf21e40"
},
"title": "galaxy s10"
}, {
"category": {
"_id": "6220db08e861f3dbbaf21e39"
},
"title": "galaxy s30"
}
]
},
mounted() {
this.products = this.products.filter(({ category }) => category._id === this.category.category._id);
}
})
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.5.17/vue.js"></script>
<div id="app">
<p>{{category.category.type}}</p>
<ul>
<li v-for="product in products" :key="product._id">
{{ product.title }}
</li>
</ul>
</div>
To get the products for a category you can filter your products :
let categoryProducts = this.products.filter((p) => {
return p.category.type == this.category.type
})
But perhaps its better to only retrive products of that category from the server, without filtering on js, if you don't need the products of other categories
i don't know your api but something like that perhaps :
axios.get(`http://localhost:5000/api/products?category=` + this.category.id, {})
.then(response => {
console.log(response);
this.product = response.data.product;
})
.catch(error => {
error;
});
mounted() {
axios
.get(`http://localhost:5000/api/categories/${this.$route.params.id}`)
.then(response => {
this.category = response.data.category;
})
.catch(error => {
console.log(error);
});
}
By above api you will get category object which have products. so you don't need any other api. so now just loop using category.products.
<div
v-for="product in category.products"
:key="product._id"
>
{{product.title}}
</div>
I use Axios to display a JSON data and I have succeeded. But I want to show an object based on date and time, it shows now all data and I need to filter it.
So I want to look at today's date and show the object based on that, so I want to show the next upcoming event. (24/05/2020)
What I currently have:
Json:
{
"doc": [
{
"data": {
"events": {
"18807612": {
"_dt": {
"_doc": "time",
"time": "18:45",
"date": "14/05/20",
"tz": "UTC",
"tzoffset": 0,
"uts": 1566067500
},
"week": 33,
"teams": {
"home": {
"name": "name 1",
"mediumname": "name1",
"uid": 3014
},
"away": {
"name": "name 2",
"mediumname": "name 2",
"uid": 3020
}
}
},
"18807618": {
"_dt": {
"_doc": "time",
"time": "18:45",
"date": "24/05/20",
"tz": "UTC",
"tzoffset": 0,
"uts": 1566067500
},
"week": 33,
"teams": {
"home": {
"name": "name 1",
"mediumname": "name1",
"uid": 3014
},
"away": {
"name": "name 2",
"mediumname": "name2",
"uid": 3020
}
}
}
}
}
}
]
}
Store:
async loadPosts({ commit }) {
// Define urls pages
const urlEvents = 'http://api.example.com/302020';
// Set pages
const [
responseEvents
] = await Promise.all([
// Responses pages
this.$axios.get(urlEvents)
]);
// variables pages
this.events = responseEvents.data.doc[0].data.events
// mutations pages
commit('SET_EVENTS', this.events)
}
},
mutations: {
SET_EVENTS (state, events) {
state.events = events;
}
}
And to show the data I use this:
import {mapState} from 'vuex';
export default {
name: 'NextMatch',
mounted() {
this.$store.dispatch('loadPosts')
},
computed: {
...mapState([
'events'
])
}
}
<h1>{{events}}</h1>
But this shows all data, and what I try to get is the first upcoming event for the object with the "uid": 3014.
So I want to show the date, time and names of the home and away team.
How can I get the correct data by filtering the data?
Something like this or similar to this should work:
In your Vue component's <template>:
`<h1>{{selectedEvent._dt.date}}</h1>`
In your Vue component's <script>:
props: {
eventID: {
type: Number,
default: 3014
},
},
computed: {
...mapState([
'events'
]),
eventsArr(){
if (!this.events) return {} //make sure Object.entries gets object.
return Object.entries(this.events)
},
selectedEvent(){
const selectedArr = this.eventsArr.find(([eID, e]) => e.teams.home.uid === this.eventID)
return selectedArr[1]
}
}
first question here.
when i try to run this, it does fetch data in the response.data, but that data is not set into state to be passed through as prop to another page and it always stays [Object object] or [undefined] & i have no clue what's going wrong
state = {
APiData: {},
userInput: "cheese",
onCall: false
}
findFood = () => {
let self = this;
let userInput = this.state.userInput.toLowerCase();
let url = "https://api.spoonacular.com/recipes/search?query=" + userInput + "&number=1&apiKey="+apiKey;
axios.get(url)
.then(function (response) {
console.log(response.data); //get's data
self.setState({APIdata: response.data});
})
.catch(function (error) {
console.log(error)
});
}
renderbody = () => {
console.log(this.state.APIdata) //this thing, is undefined
// return (<SearchBody data={this.state.APIdata} key={apiKey}/>)
}
this is the data in response.data
"baseUri": "https://spoonacular.com/recipeImages/",
"expires": 1585843318293,
"isStale": false,
"number": 1,
"offset": 0,
"processingTimeMs": 437,
"results": Array [
Object {
"id": 215435,
"image": "three-cheese-pizza-for-cheese-lovers-215435.jpg",
"imageUrls": Array [
"three-cheese-pizza-for-cheese-lovers-215435.jpg",
],
"readyInMinutes": 45,
"servings": 8,
"title": "Three-Cheese Pizza (For Cheese Lovers)",
},
],
"totalResults": 855,
}
Object {
"baseUri": "https://spoonacular.com/recipeImages/",
"expires": 1585843318293,
"isStale": false,
"number": 1,
"offset": 0,
"processingTimeMs": 437,
"results": Array [
Object {
"id": 215435,
"image": "three-cheese-pizza-for-cheese-lovers-215435.jpg",
"imageUrls": Array [
"three-cheese-pizza-for-cheese-lovers-215435.jpg",
],
"readyInMinutes": 45,
"servings": 8,
"title": "Three-Cheese Pizza (For Cheese Lovers)",
},
],
"totalResults": 855,
}
You are not using state. Your state needs to be inside your constructor
constructor(props) {
super(props);
this.state = {
APiData: {},
userInput: "cheese",
onCall: false
}
}
Then, you just need to call this.setState({ APIdata: response.data });
I would recommend you to use react-redux to get data using this.props.
I am having a hard time trying to populate a v-select component with data from backend. The backend data is in json format.
The array 'items_category' is not storing the data. So I see "No data available" in my v-select. Can anyone help me. Thanks. This is my code:
<v-select v-model="category" :items="items_category" chips dense></v-select>
data () {
return {
category: '',
items_category: [],
categories: [],
i: 0
}
},
created () {
this.initialize()
},
methods: {
initialize () {
axios.get('http://localhost:4000/categories', {
})
.then(response => {
this.categories = response.data
for (this.i=0; this.i<this.categories.length; this.i++) {
this.items_category[this.i] = this.categories[this.i].category_name
}
})
.catch(function (error) {
console.log(error);
})
}
}
This is my json (http://localhost:4000/categories):
[
{
"id": 1,
"category_name": "Name 1",
"category_description": "Description 1"
},
{
"id": 2,
"category_name": "Premium",
"category_description": "Description 2"
},
{
"id": 3,
"category_name": "Free",
"category_description": "Description 3"
}
]
Ok I got it correct by using the push method
this.items_category.push(this.categories[this.i].category_name)
i am working a typeahead. and my typeahead accept a array list like ['Canada', 'USA', 'Mexico'].
and now i have a axios api to get a list of country. but i don't know how can i convert to a array list. Now work if hardcode a country list.
<vue-bootstrap-typeahead
:data="addresses"
v-model="addressSearch"
/>
data() {
return {
addresses: ['Canada', 'USA', 'Mexico'],
addressSearch: '',
}
},
axios.get('api_link', {})
.then(function (response) {
//How can i create a array list from api return useing name like addresses?
})
And my api return:
[
{
"id": 1,
"name": "Canada"
},
{
"id": 2,
"name": "USA"
},
]
Make use of the created() lifecycle hook to get the data:
created() {
axios.get('api_link', {})
.then((response) => { this.addresses = response.data.map(x => x.name) })
}
In your data() make sure to initialize to an empty array:
data() {
return {
addresses: [],
...
}
Just so you see what the map function does:
console.log([ { "id": 1, "name": "Canada" }, { "id": 2, "name": "USA" }, ].map(x=>x.name))
You can use array.map to take only the names like this:
axios.get('api_link', {})
.then((response) => {
this.addresses = response.data.map(country => country.name)
})