I have content rendering on the page but my image can't show on screen.I think that I forgot something.This is a error displaying in the console.[Vue warn]: Data property "collection" is already defined in Props. at <ShoppingCart collection= CartCollection {items: Array(3)} > at
there is come code of some components. App.vue
<template>
<ShoppingCart :collection="cartItems" />
</template>
<script lang="ts">
import { Vue, Options } from 'vue-class-component';
import { CartCollection } from './CartItems';
import ShoppingCart from './components/ShoppingCart.vue';
const shoppingCartItems = new CartCollection();
@Options({
components: {
ShoppingCart,
},
})
export default class App extends Vue {
data() {
return {
cartItems: shoppingCartItems,
};
}
handleBroadcastEvent(event: string) {
console.log(`VUE: App.handleBroadcastEvent : ${event}`);
}
}
</script>
<style scoped></style>
ShoppingCart.vue
<template>
<div >
<div v-if="!isCheckingOut">
<h2>Shopping Cart</h2>
<hr />
<div v-bind:key="item.id" v-for="item in collection.items">
<ItemView :item="item" @on-remove="onItemRemoved"></ItemView>
</div>
<button v-on:click="checkout">Checkout</button>
</div>
<div v-if="isCheckingOut">
<h2>Check Out</h2>
<hr />
<CheckoutView :basket="collection"></CheckoutView>
<button v-on:click="back()">Back</button>
<button >Place Order</button>
</div>
</div>
</template>
<script lang="ts">
import { Options, Vue } from 'vue-class-component';
import { CartCollection } from '../CartItems';
import ItemView from './ItemView.vue';
import CheckoutView from './CheckoutView.vue';
@Options({
props: {
collection: CartCollection,
},
components: {
ItemView,
CheckoutView,
},
})
export default class ShoppingCart extends Vue {
collection!: CartCollection;
isCheckingOut!: boolean;
data() {
return {
collection: this.collection,
isCheckingOut: false,
};
}
onItemRemoved(id: number) {
const index = this.collection.items.findIndex((item) => item.id === id);
this.collection.items.splice(index, 1);
}
checkout() {
this.isCheckingOut = true;
}
back() {
this.isCheckingOut = false;
}
}
</script>
CartItems.ts
export interface IProduct {
id: number;
name: string;
type: string;
image: string;
longDescription?: string;
specs: ISpecs;
amount?: number;
}
export interface ISpecs {
actuationForce?: string;
actuationPoint?: string;
bottomOut?: string;
bottomOutTravel?: string;
price: string;
}
export class CartCollection {
items: IProduct[];
constructor() {
this.items = [
{
id: 1,
name: 'Holy Panda',
type: 'Tactile',
image:
'https://ih0.redbubble.net/image.618638614.1485/raf,750x1000,075,t,fafafa:ca443f4786.jpg',
longDescription:
'The giant panda (Ailuropoda melanoleuca; Chinese: 大熊猫; pinyin: dàxióngmāo),[4] also known as the panda bear (or simply the panda), is a bear species endemic to China. It is characterised by its bold black-and-white coat and rotund body. The name "giant panda" is sometimes used to distinguish it from the red panda, a neighboring musteloid. Though it belongs to the order Carnivora, the giant panda is a folivore, with bamboo shoots and leaves making up more than 99% of its diet.[5] Giant pandas in the wild will occasionally eat other grasses, wild tubers, or even meat in the form of birds, rodents, or carrion. In captivity, they may receive honey, eggs, fish, yams, shrub leaves, oranges, or bananas along with specially prepared food.',
specs: {
actuationForce: '44',
actuationPoint: '2.4',
bottomOut: '62',
bottomOutTravel: '3.8',
price: '1.60',
},
},
{
id: 2,
name: 'Engagement Rings',
type: 'Tactile',
image:
'https://jewelryjealousy.com/wp-content/uploads/2018/10/best-square-engagement-ring.jpg',
longDescription:
'Instead of having pre-made rings with price tags on them, our goal is to create one amazing ring that fits your budget - something made just for the love of your life, for the price of something off the shelf.',
specs: {
actuationForce: '74',
actuationPoint: '2.8',
bottomOut: '72',
bottomOutTravel: '6.8',
price: '100.60',
},
},
{
id: 1,
name: 'Football',
type: 'Tactile',
image: 'https://pngimg.com/uploads/football/football_PNG52759.png',
longDescription:
'Football is a family of team sports that involve, to varying degrees, kicking a ball to score a goal. Unqualified, the word football normally means the form of football that is the most popular where the word is used. Sports commonly called football include association football (known as soccer in North America and Oceania); gridiron football (specifically American football or Canadian football); Australian rules football; rugby union and rugby league; and Gaelic football.[1] These various forms of football share to varying extent common origins and are known as football codes.',
specs: {
actuationForce: '74',
actuationPoint: '6.5',
bottomOut: '32',
bottomOutTravel: '3.8',
price: '10.60',
},
},
];
}
}
CodePudding user response:
Probably the issue is that you have defined "collection" both in props and in data. Try renaming one of them.
CodePudding user response:
You can't have the same key defined in more than one of the following Options API sections:
props: { myKey: ... }
data: () => ({ myKey: ... } )
computed: { myKey: ... }
methods: { myKey: ... }
Ultimately, all of the above are referencing the same object (the component instance) and you can't have the same key defined in more than one section.
In your case, you are using the key collection
in both props
and data
.
If you're thinking: "but I'm not using the Options API, I'm using Component Class API!", well, you're not exactly right.
Under the hood, Class API is just syntactic sugar for Options API.
You are, actually, using Options API.
In more detail, the collection
key needs to change in one of the following, to make the error disappear and your component work as expected:
@Options({
props: {
collection: CartCollection,
}
})
and
class ShoppingCart extends Vue {
data() {
return {
collection: this.collection,
};
}
}
If you want to make you collection
editable, you can't really, as it's a prop (and you can't edit props inside children because any change in the parent component would override your changes).
The way to handle that is to delegate the change to the parent component and then receive it back into the child component via props
:
Here's how that would look like, in your case:
export default {
props: ['collection'],
computed: {
localCollection: {
get() {
return this.collection;
},
set(val) {
this.$emit('update:collection', val);
}
}
}
}
and, in parent component, your child component would look like:
<cart-collection :collection.sync="someCollection" />
You still can't edit collection
, but you can edit localCollection
and any change to it would actually trigger a change to collection
in parent component and, subsequently, to collection
, reflect back into localCollection
, through the getter.