I have products two types: simple and configurable:
"products" : [
{
"type": "simple",
"id": 1,
"sku": "s1",
"title": "Product 1",
"regular_price": {
"currency": "USD",
"value": 27.12
},
"image": "/images/1.png",
"brand": 9
},
{
"type": "configurable",
"id": 2,
"sku": "c1",
"title": "Product 2",
"regular_price": {
"currency": "USD",
"value": 54.21
},
"image": "/images/conf/default.png",
"configurable_options": [
{
"attribute_id": 93,
"attribute_code": "color",
"label": "Color",
"values": [
{
"label": "Red",
"value_index": 931,
"value": "#ff0000"
},
{
"label": "Blue",
"value_index": 932,
"value": "#0000ff"
},
{
"label": "Black",
"value_index": 933,
"value": "#000"
}
]
},
{
"attribute_code": "size",
"attribute_id": 144,
"position": 0,
"id": 2,
"label": "Size",
"values": [
{
"label": "M",
"value_index": 1441,
"value": 1
},
{
"label": "L",
"value_index": 1442,
"value": 2
}
]
}
],
"variants": [
{
"attributes": [
{
"code": "color",
"value_index": 931
},
{
"code": "size",
"value_index": 1441
}
],
"product": {
"id": 2001,
"sku": "c1-red-m",
"image": "/image/conf/red.png"
}
},
{
"attributes": [
{
"code": "color",
"value_index": 931
},
{
"code": "size",
"value_index": 1442
}
],
"product": {
"id": 2002,
"sku": "c1-red-l",
"image": "/image/conf/red.png"
}
},
{
"attributes": [
{
"code": "color",
"value_index": 932
},
{
"code": "size",
"value_index": 1441
}
],
"product": {
"id": 2003,
"sku": "c1-blue-m",
"image": "/image/conf/blue.png"
}
},
{
"attributes": [
{
"code": "color",
"value_index": 933
},
{
"code": "size",
"value_index": 1442
}
],
"product": {
"id": 2004,
"sku": "c1-black-l",
"image": "/image/conf/black.png"
}
}
],
"brand": 1
}
]
The above data I get with actions (Vuex)
GET_PRODUCTS_FROM_API({ commit }) {
return axios('http://localhost:8080/products', {
method: 'GET',
})
.then((products) => {
commit('SET_PRODUCTS_TO_STATE', products.data);
return products;
})
.catch((e) => {
console.log(e);
return e;
});
}
then I mutate the data:
SET_PRODUCTS_TO_STATE: (state, products) => {
state.products = products
}
and get from in getters
PRODUCTS(state) {
return state.products = state.products.map((product) => {
const brand = state.brands.find((b) => b.id === product.brand)
return {...product, brandName: brand?.title || 'no brand'}
})
}
after which i get the data in the component
At the moment I'm stuck on how to render the color and size attributes of a configurable product. Tell me how to do it right? Do I need to write logic in vuex or parent component?
I tried to push data from parent component to child. But it stopped there again.
I also tried to separate the color and size attributes separately using getters.
For Vuex, the syntax is the following
<template>
<div>
<div v-for="product in products" :key="product.id">
<span>type: {{ product.type }}</span>
<span>type: {{ product.title }}</span>
</div>
</div>
</template>
<script>
import { mapGetters } from 'vuex'
export default {
computed: {
...mapGetters(['products']),
...mapGetters('fancyNamespace', ['products']), // if namespaced
},
}
</script>
As of where to call it, directly into the component I guess. Otherwise, as explained here it may not be relevant to use Vuex at all.
PS: you can even rename on the fly if you want.
Solved this issue by Computed Properties and transfer props to child components
computed: {
getAttributeColors() {
let attributes_colors = []
this.product_data.configurable_options.map((item) => {
if(item.label === 'Color') {
attributes_colors.push(item.values)
}
})
return attributes_colors
},
getAttributeSize() {
let attributes_size = []
this.product_data.configurable_options.map((item) => {
if(item.label === 'Size') {
attributes_size.push(item.values)
}
})
return attributes_size
}
}
Related
API Request
/store-api/product-listing/{categoryId}
I want each product in the API response to have available color variants. Because I want to show color variants on the product list page. But currently this data is not provided by the shopware 6 api.
I've tried to add this data by using associations but it didnt help.
Request Body
{
"includes": {
"product": ["id", "productNumber", "cover", "options"]
},
"associations": {
"options": {
"media": []
}
}
}
The request body looks to be correct. If the product is a variant then it should have content for options.
To verify try the following request body:
{
"limit": 1,
"includes": {
"product": ["id", "productNumber", "options"],
"property_group_option": ["name", "group"],
"property_group": ["name"]
},
"associations": {
"options": {
"associations": {
"group": []
}
}
},
"filters": [
{
"type": "not",
"operator": "and",
"queries": [
{
"type": "equals",
"field": "parentId",
"value": null
}
]
}
]
}
This should yield a single variant.
Response should look similar to this:
{
"entity": "product",
"total": 1,
"aggregations": [],
"page": 1,
"limit": 1,
"elements": [
{
"productNumber": "10042.1",
"options": [
{
"name": "linen",
"group": {
"name": "textile",
"apiAlias": "property_group"
},
"apiAlias": "property_group_option"
},
{
"name": "35",
"group": {
"name": "size",
"apiAlias": "property_group"
},
"apiAlias": "property_group_option"
},
{
"name": "chartreuse",
"group": {
"name": "shirt-color",
"apiAlias": "property_group"
},
"apiAlias": "property_group_option"
}
],
"id": "0002ea44c49c41ecb91c43e7e49e422d",
"apiAlias": "product"
}
],
"states": [],
"apiAlias": "dal_entity_search_result"
}
The task is to add a product with selection options to the cart. For example, take product with id:2, which has different color and size options. By clicking on the add product button, the product of the selected option should be added to the cart. Product options are predefined. You can see them in the products array below. At the moment, I have created a cart entity in the global store, where I can add a product without selection options and render it on the cart page.
"products" : [
{
"type": "simple",
"id": 1,
"sku": "s1",
"title": "Product 1",
"regular_price": {
"currency": "USD",
"value": 27.12
},
"image": "/images/1.png",
"brand": 9
},
{
"type": "configurable",
"id": 2,
"sku": "c1",
"title": "Product 2",
"regular_price": {
"currency": "USD",
"value": 54.21
},
"image": "/images/conf/default.png",
"configurable_options": [
{
"attribute_id": 93,
"attribute_code": "color",
"label": "Color",
"values": [
{
"label": "Red",
"value_index": 931,
"value": "#ff0000"
},
{
"label": "Blue",
"value_index": 932,
"value": "#0000ff"
},
{
"label": "Black",
"value_index": 933,
"value": "#000"
}
]
},
{
"attribute_code": "size",
"attribute_id": 144,
"position": 0,
"id": 2,
"label": "Size",
"values": [
{
"label": "M",
"value_index": 1441,
"value": 1
},
{
"label": "L",
"value_index": 1442,
"value": 2
}
]
}
],
"variants": [
{
"attributes": [
{
"code": "color",
"value_index": 931
},
{
"code": "size",
"value_index": 1441
}
],
"product": {
"id": 2001,
"sku": "c1-red-m",
"image": "/image/conf/red.png"
}
},
{
"attributes": [
{
"code": "color",
"value_index": 931
},
{
"code": "size",
"value_index": 1442
}
],
"product": {
"id": 2002,
"sku": "c1-red-l",
"image": "/image/conf/red.png"
}
},
{
"attributes": [
{
"code": "color",
"value_index": 932
},
{
"code": "size",
"value_index": 1441
}
],
"product": {
"id": 2003,
"sku": "c1-blue-m",
"image": "/image/conf/blue.png"
}
},
{
"attributes": [
{
"code": "color",
"value_index": 933
},
{
"code": "size",
"value_index": 1442
}
],
"product": {
"id": 2004,
"sku": "c1-black-l",
"image": "/image/conf/black.png"
}
}
],
"brand": 1
}]
My store:
import {createStore} from 'vuex'
import apiRequests from "#/store/actions/apiRequests";
import commonActions from './actions/actions'
import mutations from './mutations/mutations'
import getters from './getters/getters'
const actions = {...commonActions, ...apiRequests}
export default createStore({
state: {
products: [],
brands: [],
cart: []
},
mutations,
actions,
getters
})
actions:
export default {
ADD_TO_CART({commit}, product) {
commit('SET_CART', product)
},
INCREMENT_CART_ITEM({commit}, index) {
commit('INCREMENT', index)
},
DECREMENT_CART_ITEM({commit}, index) {
commit('DECREMENT', index)
},
DELETE_FROM_CART({commit}, index) {
commit('REMOVE_ITEM_FROM_CART', index)
}
}
mutations:
export default {
SET_PRODUCTS_TO_STATE: (state, products) => {
state.products = products
},
SET_BRANDS_TO_STATE: (state, brands) => {
const includesBrands = {}
for (const brand of brands) {
for (const product of state.products) {
if (product.brand === brand.id) {
includesBrands[brand.id] = brand
}
}
}
state.brands = Object.values(includesBrands)
state.brands.unshift({title: "All brands"})
},
SET_CART: (state, product) => {
if (state.cart.length) {
let isProductExists = false
state.cart.map((item) => {
if (item.id === product.id) {
isProductExists = true
item.quantity++
}
})
if (!isProductExists) {
state.cart.push({...product, quantity: 1})
}
} else {
state.cart.push({...product, quantity: 1})
}
},
REMOVE_ITEM_FROM_CART: (state, index) => {
state.cart.splice(index, 1)
},
INCREMENT: (state, index) => {
state.cart[index].quantity++
},
DECREMENT: (state, index) => {
if (state.cart[index].quantity > 1) {
state.cart[index].quantity--
}
}
}
and getters:
export default {
BRANDS(state) {
return state.brands
},
CART(state) {
return state.cart
},
PRODUCTS(state) {
return state.products = state.products.map((product) => {
const brand = state.brands.find((b) => b.id === product.brand)
return {...product, brandName: brand?.title || 'no brand'}
})
},
}
Now I am faced with the fact that I do not understand how I can add a certain product variant to the cart and draw it on the cart page.
I am trying to loop through the following JSON:
[ { "target": { "source": "https://firebasestorage.googleapis.com/v0/b/vue-photoapp-api.appspot.com/o/photos%2Fmountains-hero.jpg?alt=media&token=fbe93188-d13d-4a7f-a472-4a529aa565a0", "selector": { "conformsTo": "http://www.w3.org/TR/media-frags/", "value": "xywh=pixel:378.2608642578125,328.9855041503906,147.82611083984375,210.14492797851562", "type": "FragmentSelector" } }, "photoDocId": "92wNwz2aaqy7CWf3mGo1", "body": [ { "value": "new annotation", "purpose": "commenting", "type": "TextualBody" }, { "purpose": "tagging", "type": "TextualBody", "value": "error" } ], "id": "698RTBGMwWahQ15rXbe6", "type": "Annotation", "#context": "http://www.w3.org/ns/anno.jsonld" }, { "photoDocId": "92wNwz2aaqy7CWf3mGo1", "target": { "source": "https://firebasestorage.googleapis.com/v0/b/vue-photoapp-api.appspot.com/o/photos%2Fmountains-hero.jpg?alt=media&token=fbe93188-d13d-4a7f-a472-4a529aa565a0", "selector": { "conformsTo": "http://www.w3.org/TR/media-frags/", "value": "xywh=pixel:695.6521606445312,60.869564056396484,139.13043212890625,127.53622817993164", "type": "FragmentSelector" } }, "id": "AUMwWBjizjl8L8vU0XtA", "#context": "http://www.w3.org/ns/anno.jsonld", "type": "Annotation", "body": [ { "value": "clouds!", "type": "TextualBody", "purpose": "commenting" }, { "type": "TextualBody", "value": "clouds", "purpose": "tagging" } ] }, { "type": "Annotation", "body": [ { "type": "TextualBody", "value": "fourth anno", "purpose": "commenting" } ], "target": { "source": "https://firebasestorage.googleapis.com/v0/b/vue-photoapp-api.appspot.com/o/photos%2Fmountains-hero.jpg?alt=media&token=fbe93188-d13d-4a7f-a472-4a529aa565a0", "selector": { "type": "FragmentSelector", "conformsTo": "http://www.w3.org/TR/media-frags/", "value": "xywh=pixel:631.884033203125,389.8551025390625,172.4637451171875,128.9854736328125" } }, "#context": "http://www.w3.org/ns/anno.jsonld", "id": "CecyGAt47krNIOPgk8Su", "photoDocId": "92wNwz2aaqy7CWf3mGo1" }, { "photoDocId": "92wNwz2aaqy7CWf3mGo1", "body": [ { "type": "TextualBody", "purpose": "commenting", "value": "mountain top . Anyone ever climbed this?" }, { "value": "mountain", "type": "TextualBody", "purpose": "tagging" } ], "#context": "http://www.w3.org/ns/anno.jsonld", "id": "KxIMdih1fTSULjde3Ay4", "type": "Annotation", "target": { "selector": { "type": "FragmentSelector", "value": "xywh=pixel:272.4637756347656,60.869564056396484,252.17391967773438,185.50725173950195", "conformsTo": "http://www.w3.org/TR/media-frags/" }, "source": "https://firebasestorage.googleapis.com/v0/b/vue-photoapp-api.appspot.com/o/photos%2Fmountains-hero.jpg?alt=media&token=fbe93188-d13d-4a7f-a472-4a529aa565a0" } } ]
I want to return just the following values:
purpose, type, and value. They are located within the body array of clientAnnos
Will this need to be a v-for within a v-for loop?
Update: I tried:
<ul>
<li v-for="{ body, index } in clientAnnos" :key="index">
{{ body }}
</li>
</ul>
But I am wondering if there's possible update issues due to index variable not having a true id.
you can try by mapping through the data then looping through the body since its an array. You can use a method for this for example
methods: {
info() {
let required = this.data.map(d => d.body)
return required
}
}
Then use the blog as a data value in the v for. The method will return an array of the body array properties
<li v-for="{ body, index } in info" :key="index">
{{ body }}
</li>
I hope it helps...
I have the below json structure
{
"title": "Name(s)",
"type": "Text",
"data": [
{
"source": "DB",
"title": "All",
"list": [
{
"name": "ABCD",
"count": 1
},
{
"name": "BCDE",
"count": 1
},
{
"name": "CDEF",
"count": 1
},
{
"name": "DEFG",
"count": 2
},
{
"name": "EFGH",
"count": 1
}
]
}
]
},
{
"title": "Category(s)",
"type": "Text",
"data": [
{
"source": "DB",
"title": "All",
"list": [
{
"name": "Vegetables",
"count": 1942
},
{
"name": "Saloon",
"count": 355
},
{
"name": "General Store",
"count": 331
},
{
"name": "Restaurants",
"count": 130
},
{
"name": "Fast Food",
"count": 108
}
]
}
]
}
I am trying to show the data as Like
1st SectionHeader : "Name(s)"
1stRow: "ABCD"
2ndRow "BCDE"
3rdRow "CDEF"
.
.
.
2nd SectionHeader : "Category(s)"
1stRow: "Vegetables"
2ndRow "Saloon"
3rdRow "General Store"
.
.
.
Here, should I use SectionList/Flatlist/ Mix both of them to get the above result.
In flatlist/sectionlist I am getting the section header Names(s)& Category(s) in renderSectionHeader but in renderItem,
How Can I loop the "list" array of objects.
Kindly let me know
You have to update the data like the following,
eg:
[
{
"title": "Name(s)",
"type": "Text",
"data": [
{
"name": "ABCD",
"count": 1
},
{
"name": "BCDE",
"count": 1
},
...
]
},
{
"title": "Category(s)",
"type": "Text",
"data": [
{
"name": "Vegetables",
"count": 1942
},
{
"name": "Saloon",
"count": 355
},
...
]
}
...
]
And use SectionList for display it,
eg:
...
<SectionList
renderItem={({item, index, section}) => <Text key={index}>{item.name}</Text>}
renderSectionHeader={({section: {title}}) => (
<Text style={{fontWeight: 'bold'}}>{title}</Text>
)}
sections={this.state.data}
keyExtractor={(item, index) => item + index}
/>
...
How do I add a legend to a basic chart in Vega?
I'm using Vega in the web app where I want all my charts to include a legend even if its a single series.
i.e in Google Sheets it looks like
Since Datum hasn't been implemented yet I added an extra layer as a workaround (This also works for Multi Series Charts by adding additional values into data.values for the rule.)
{
"mark": {
"type": "rule"
},
"data": {
"values": [
{
"color": "Total Units"
}
]
},
"encoding": {
"color": {
"field": "color",
// If you want to update the color of the legend...
"scale": {"range": ["blue", "#000"]},
"sort": false,
"type": "nominal",
"legend": { "title": "" }
}
}
}
Also for those that want to view an example in VegaLite Editor https://vega.github.io/editor/#/
{
"layer": [
{
"mark": "bar",
"data": {
"values": [
{
"goal": 25,
"project": "a",
"score": 25
},
{
"goal": 47,
"project": "b",
"score": 57
},
{
"goal": 30,
"project": "c",
"score": 23
},
{
"goal": 27,
"project": "d",
"score": 19
}
]
},
"encoding": {
"x": {
"type": "nominal",
"field": "project"
},
"y": {
"type": "quantitative",
"field": "score"
}
},
"height": 300,
"width": 400
},
{
"mark": {
"type": "rule"
},
"data": {
"values": [
{
"color": "Goal"
}
]
},
"encoding": {
"color": {
"field": "color",
"sort": false,
"type": "nominal",
"legend": { "title": "" }
}
}
}
]
}