Mutating a mutable prop directly the computed set handler were not called - vue.js

Reproduction link
https://codesandbox.io/embed/musing-kirch-ss507?fontsize=14&hidenavigation=1&theme=dark
I change the prop but the set handler were not called, something I am ignored?
Thanks.

You are updating test property of dTest - but your setter is defined on dTest as a whole and not on its key test.
If you want your setter to be called - you should mutate the test computed property:
<div id="app">
<img alt="Vue logo" src="./assets/logo.png">
<HelloWorld msg="Welcome to Your Vue.js App" :test.sync="test"/>
</div>
<template>
<div class="hello">
{{ test.test }}
<button #click="change">click</button>
</div>
</template>
<script>
export default {
name: 'HelloWorld',
props: ['test'],
methods: {
change() {
// this.test = '.python'
this.$emit('update:test',{test: this.test.test.concat([1])});
}
}
}
</script>

Related

Sending object as a props in Vue.js and getting TypeError and Warning

I am trying to pass an object into my child component but it comes undefined. So my parent component:
<template>
<section id="cart-page" class="row">
<div v-for="items in cart" :key="items.product.id">
<div class="col-lg-8 col-md-12 col-sm-12 col-xs-12">
<div class="title">WARENKORB</div>
<SoldTickets :items = "items"/>
</div>
</div>
</section>
</template>
<script>
import image from "../../../../img/Hallenbad.jpg";
import CheckBox from "../components/CheckBox";
import SoldTickets from "../components/SoldTickets";
export default {
components: {
CheckBox,
SoldTickets,
},
data(){
return {
image: image,
};
},
computed: {
cart() {
return this.$store.state.cart;
},
},
};
</script>
So I store cart into Vuex store and I am taking it right and it is an object like in the below:
So I want to send this cart.attributes.items object to SoldTickets component to display them inside of the component.
<template>
<div id="sold-tickets">
<div class="card">
<div class="sold-tickets-actions">
<div class="sold-tickets-inner">
<img class="sold-tickets-image" :src="image" alt="Sold Ticket"/>
</div>
</div>
<div class="sold-tickets-actions properties">
<div class="sold-tickets-inner">
<div class="ticket-details">
<div class="ticket-prop">
<div class="ticket-name">{{ items.product_name }}</div>
<div class="ticket-type">{{ items.variation_name }}</div>
</div>
</div>
<DeleteButton />
</div>
</div>
</div>
</div>
</template>
<script>
import image from "../../../../img/Hallenbad.jpg";
import DeleteButton from "./DeleteButton";
import cartHelper from "../helpers/cartHelper";
export default {
props: {
items: Object,
},
components: {DeleteButton},
data() {
return {
image: image,
};
},
};
</script>
But I am getting errors. vue.esm.js:628 [Vue warn]: Error in render: "TypeError: Cannot read properties of undefined (reading 'id')" and TypeError: Cannot read properties of undefined (reading 'id'). And if I delete ':key="items.product.id"' from parent component this time I am getting a warning but items cannot be displayed again. [Vue warn]: Invalid prop: type check failed for prop "items". Expected Object, got String with value "00e84ffb-1fbf-00bf-d3cc-adbcc795e060" and [Vue warn]: Invalid prop: type check failed for prop "items". Expected Object, got String with value "carts"
But the thing is if I try to display the items in the parent component, it works without warning & erros. So why do you think it is happening? Thanks for the helps.
The problem here is that items are an array of objects, as can be seen from the console.log(), but you treat it as an object in your code. You can change that by either passing a certain object to the child component like this:
<div v-for="items in cart" :key="items.product.id">
<div class="col-lg-8 col-md-12 col-sm-12 col-xs-12">
<div class="title">WARENKORB</div>
<SoldTickets :items = "items[0]"/> --> only pass first object
</div>
</div>
Or you change your child component to accept arrays and then loop through the array in the template like this:
<template>
<div id="sold-tickets">
<div class="card">
<div class="sold-tickets-actions">
<div class="sold-tickets-inner">
<img class="sold-tickets-image" :src="image" alt="Sold Ticket"/>
</div>
</div>
<div v-for="item in items" :key="item.product.id" class="sold-tickets-actions properties">
<div class="sold-tickets-inner">
<div class="ticket-details">
<div class="ticket-prop">
<div class="ticket-name">{{ item.product_name }}</div>
<div class="ticket-type">{{ item.variation_name }}</div>
</div>
</div>
<DeleteButton />
</div>
</div>
</div>
</div>
</template>
<script>
import image from "../../../../img/Hallenbad.jpg";
import DeleteButton from "./DeleteButton";
import cartHelper from "../helpers/cartHelper";
export default {
props: {
items: Array,
},
components: {DeleteButton},
data() {
return {
image: image,
};
},
};
</script>
The problem is that you are looping through the object cart which has many keys, and some of their values are strings (eg: "00e84ffb-1fbf-00bf-d3cc-adbcc795e060"), at the same time your child component expects to receive an object. That's why it's spitting out the errors. You can read more about List Rendering with an Object here.
My suggestion:
If you need cart.attributes.items in your child component, then just send it, change your computed property cart to an array:
computed: {
cart() {
return this.$store.state.cart.attributes?.items || [];
}
}
in the template, passing item array into the child component, the variable item should be in singular form, you can name whatever you want, but for the sake of clarity, please use singular form:
<div v-for="item in cart" :key="item.id">
<div class="col-lg-8 col-md-12 col-sm-12 col-xs-12">
<div class="title">WARENKORB</div>
<SoldTickets :item = "item"/>
</div>
</div>
don't forget to change your props declaration:
props: {
items: Array,
}

[Vue warn]: Missing required prop: "productInfo"

I'm fairly new to Vue so this may be obvious, but I must be missing something. I keep getting the error: [Vue warn]: Missing required prop: "productInfo" in my .vue file. It says its found in ProductSlider.vue.
ProductSlider.vue
<template>
<div
id="recommendedProducts">
<h2>{{ params.headerText }}</h2>
<div
class="wrapper">
<div class="carousel-view">
<carousel
:navigation-enabled="true"
:min-swipe-distance="1"
:per-page="5"
navigation-next-label="<i class='fas fa-3x fa-angle-right'></i>"
navigation-prev-label="<i class='fas fa-3x fa-angle-left'></i>">
<slide
v-for="product in products"
:key="product.id">
<Product
:id="product.id"
:product-info="product"/>
</slide>
</carousel>
</div>
</div>
</div>
</template>
<script>
import Slider from './Slider'
import Product from './Product'
import {mapState, mapGetters} from 'vuex'
import axios from 'axios';
export default {
name: "Slider",
components: {
Product
},
props: {
productInfo: {
type: Object,
required: true
}
},
I chopped off the end of the ProductSlider code because the rest is very long and irrelevant.
And then here is my Product.vue:
<template>
<Product>
<div class="img-container text-center">
<a
:href="productInfo.href"
class="handCursor"
tabindex="0">
<img
v-if="productInfo.imgOverlay"
:src="productInfo.imgOverlayPath"
:alt="productInfo.title"
:aria-label="productInfo.title"
border="0"
tabindex="-1">
<img
:src="productInfo.imgURL"
:alt="productInfo.title">
</a>
</div>
<h4 class="itemTitle">{{ productInfo.title }}</h4>
<div class="price-div">
<div class="allPriceDescriptionPage">{{ productInfo.price }}</div>
</div>
<a
href="#"
tabindex="0"
name="instantadd">
<div class="btn_CA_Search buttonSearch gradient"> Add to Cart</div>
</a>
</Product>
</template>
<script>
export default {
name: "Product",
props: {
productInfo: {
type: Object,
required: true,
},
},
}
</script>
I have productInfo in the props so I'm not sure why I keep getting this error.
I think you confused props and the child component's props, when you have:
<Product
:id="product.id"
:product-info="product"/>
You have a prop productInfo defined in the child component Product, not in the component ProductSlider itself, and if you define prop productInfo in ProductSlider, then you have to pass it down from the parent component, that is you need to have <ProductSlider :product-info="..."/> whenever ProductSlider is used.
Notice <Product :product-info="product"/> doesn't mean you are using the value of productInfo, product-info is the name of prop that's defined in Product component.
I think a fair analogy to use is if you think of your component as a function, props are function parameters, and required function parameters need to provided when they are called.
For your case, to eliminate the error, you can simply remove the productInfo prop from ProductSlider component since it's not used in that component.

Update component data from the template

Not too sure what is wrong here, it seems fine to me! I'm simply trying to update the data property display to true when I click the input within my component.
I have passed the data to the slot scope, so can't see that being the issue. It just simply won't update, using a function to toggle it works, however not what I really want to do, seems pointless.
<time-select>
<div slot-scope="{ time }" class="is-inline-block">
<label for="businessHoursTimeFrom"><i class="fas fa-clock"></i> From</label>
<input type="text" name="businessHoursTimeFrom[]" v-model="time" v-on:click="display = true">
</div>
</time-select>
The code behind:
<template>
<div>
<p>{{ display }}</p>
<slot :time="time" :display="display"></slot>
<div class="picker" v-if="display">
<p>Test</p>
</div>
</div>
</template>
<script>
export default {
props: [],
data: function () {
return {
time: '',
display: false
}
},
mounted() {
},
methods: {
}
}
</script>

Laravel 5.4 Vue Declarative Rendering

In a laravel 5.4 environment I want to render the text "Example" in the .panel-heading of Example.vue. After doing npm run watch I get the following Vue warn:
'Property or method "message" is not defined on the instance but referenced during render. Make sure to declare reactive data properties in the data option.'
app.js
require('./bootstrap');
window.Vue = require('vue');
Vue.component('example', require('./components/Example.vue'));
const app = new Vue({
el: '#app',
data: {
message: 'Example'
}
});
Example.vue
<template>
<div class="container">
<div class="row">
<div class="col-md-8 col-md-offset-2">
<div class="panel panel-default">
<div class="panel-heading" >{{ message }}</div>
<div class="panel-body">
I'm an example component!
</div>
</div>
</div>
</div>
</div>
</template>
<script>
export default {
mounted() {
console.log('Component mounted.')
}
}
</script>
app.blade.php
<html>
<!-- ... -->
<body>
<div id="app">
<example></example>
</div>
<script src="{{ asset('js/app.js') }}"></script>
</body>
</html>
Your Example.vue component doesn't have access to its parent's properties. You need to define message within the same scope of the component you are trying to use it in.
You can do this by adding message as a data property in your Example component:
// Example.vue script
export default {
data() {
return {
message: 'Example',
}
},
}
Or you can pass it in as a prop:
// Example.vue script
export default {
props: ['message'],
}
In your case, you would pass a value for the message prop like this:
// in app.blade.php
<example message="Example"></example>
Here's the documentation on Vue Component props.

Vuejs 2 Sending props to xxx.vue file

Normally you send props like this way
Vue.component('child', {
// camelCase in JavaScript
props: ['myMessage'],
template: '<span>{{ myMessage }}</span>'
})
How can i achieve with require:
Vue.component('lw-login', require('./components/login.vue'));
Laravel Blade Template:
<lw-login
heading="Login"
action="{{ route('login') }}"
email="E-mailadres"
passwordrequest="{{ route('password.request') }}"
></lw-login>
login.vue:
See {{ heading }}
I am getting this error:
[Vue warn]: Property or method "heading" is not defined on the instance but referenced during render. Make sure to declare reactive data properties in the data option.
(found in at C:\Code\cms\resources\assets\js\components\login.vue)
<template>
<div class="container">
<div class="row">
<div class="col-md-12">
<div class="panel panel-default">
<div class="panel-heading">{{ heading }}</div>
<div class="panel-body">
<form class="form-horizontal" role="form" method="POST" :action="action">
etc .....
<script>
export default {
mounted() {
props: ['heading','action','passwordrequest']
}
}
</script>
Changed this:
<script>
export default {
mounted() {
props: ['heading','action','passwordrequest'],
}
}
</script>
To this :)) :
<script>
export default {
props: ['heading','action','passwordrequest'],
mounted() {
}
}
</script>