Vue props not passing correctly - vue.js

I have a component
In the component I have
export default {
name: "Modal",
props: ['showFooter'],
}
Then in the template i have
<template>
<div class='modal'>
<div class='footer' v-if='showFooter'>This is the footer</div>
</div>
</template>
THe footer doesnt display at all, if i pass the prop or not. It just says
[Vue warn]: Property or method "showFooter" is not defined on the instance but referenced during render.
Whats the issue here??
Ive also just tried
<template>
<div class='modal'>
<div class='footer' v-if='showFoot'>This is the footer</div>
</div>
</template>
export default {
name: "Modal",
props: ['showFooter'],
data(){
return {
showFoot:this.showFooter
}
}
}
Then I get told showFoot isnt defined. Which is even wierder because Im defining it right there in the data!??
Even if I just remove the property totally, and just define it in data
export default {
name: "Modal",
data(){
return {
showFoot:true
}
}
}
I still get
[Vue warn]: Property or method "showFoot" is not defined on the instance but referenced during render.
So wierd and I cant for the life of me figure it out
Its almost like the template has no access to anything I define in the data() or props of the componenet. Never seen this before

i think so you are not passing props from parent component. Ideally you can pass it from parent component and receive it in Children.
<childComponent :yourPropNameInChild="anyDataFromParentYouWantToPass" />
here this ChildComponent is rendered in your parent component.
to receive it in children you can do
export default {
name: "Modal",
props: ['yourPropNameInChild'],
}
as of for your example
<modal :showFooter="showFooter" />
in your parent you have to write above line of code
and in your child you have to receive it as you are doing
also in your example you were missing script tag

Related

Vue3 props access inside setup() returns nothing

I have a weird situation with my Vue3 component. I am trying to get a value from the props inside the setup() function. But this returns nothing.
<template>
<div class="border p-2 space-y-2">
<h2 class="text-center">Makers</h2>
{{ product.makers }}
</div>
</template>
<script>
import { ref, onMounted, toRef, toRefs } from 'vue'
import ProductStore from '../store/ProductStore'
export default {
props: {
product: Object
},
setup(props) {
console.log(props.product.makers)
},
}
</script>
The value is sent from another component like the one below
<ProductMakers :product="product"/>
But I always get undefined as my response. Any clue to resolve this problem? Am I missing something?
To my surprise, the template is always showing the value correctly. The problem is only inside the setup(). Any clue?
This means that product is reactively updated after the creation of component instance.
Updated value is supposed to be accessed in a watcher or a computed. In case a side effect like logging is needed, this is the case for a watcher:
setup(props) {
watchEffect(() => {
if (props.product.makers)
console.log(props.product.makers)
});
},

Calling function inside child component without an event?

Currently trying to use a method belonging to the parent
<p class="message-date text-center">
{{ $emit('format_date_day_month_year_time', message.date) }}
</p>
However I am getting the error.
Converting circular structure to JSON
--> starting at object with constructor 'Object'
How can I call a function inside a child component that does not rely on an event? I apologize for asking such a simple question but everything I was able to find on google is using $emit and using an event.
$emit was designed to only trigger an event on the current instance of vue. Therefore, it is not possible to receive data from another component this way.
For your case, I would suggest to use Mixins especially if you need to use certain functions among multiple vue components.
Alternately, let the child component call the the parent through $emit then receive the result from the parent through a prop.
Your code could be something as follows:
Child component
<template>
<p class="message-date text-center">
{{ date }}
</p>
</template>
<script>
export default {
name: 'Child',
props: {
date: String,
},
mounted() {
this.$emit("format-date", message.date);
},
}
</script>
Parent component
<template>
<Child :date="childDate" #format-date="formatChildDate" />
</template>
<script>
import Child from '#/components/Child';
export default {
components: {
Child,
},
data: () => ({
childDate: '',
}),
methods: {
formatChildDate(date) {
this.childDate = this.formatDateDayMonthYearTime(date)
},
formatDateDayMonthYearTime(date) {
//return the formatted date
},
},
}
</script>
with $emit you call a function where the Parent can listento.
where you are using it i would suggest a computed prop of the function.
But back to your Question here is a example of emiting and listen.
//Parent
<template>
<MyComponent #childFunction="doSomethingInParent($event)"/>
</template>
//Child
<template>
<button #click="emitStuff">
</template>
.....
methods:{
emitStuff(){
this.$emit(childFunction, somedata)
}
with the event you can give Data informations to a Parentcomponent.

How to bind a local component's data object to an external component

how do you use a local component's data attriutes to bind an external component's v-model
for example i have this component
<publish-blog>
<VueTrix v-model="form.editorContent">
</publish-blog>
so the form.editorContent there refers to the publish-blog component's form.editorContent inside data, how do I do that ?
You can pass a prop to the publish-blog component.
This would be what ever page or component you are using the publish blog on, though to be honest I'm not sure why you would not just put the VueTrix component inside of the publish-blog component.
This would be on what ever page/component you are wanting it on.
<template>
<PublishBlog :trix="trix">
<VueTrix v-model="trix" />
</PublishBlog>
</template>
<script>
import PublishBlog from './PublishBlog.vue';
export default {
components: {
PublishBlog,
},
data() {
return {
trix: '',
};
},
};
</script>
and inside of the publish blog component make the form.editorContent the prop passed or a default value.
But without a global store/state you are stuck with props.
UPDATE: Showing what a publish blog component might look like
PublishBlog.vue
<template>
<section>
what ever goes here.
<slot />
</section>
</template>
<script>
export default {
name: 'PublishBlog',
props: {
trix: {
type: String,
default: '',
},
},
data() {
return {
form: {
editorContent: this.trix
},
};
},
};
</script>

Overriding a props type in child component?

I'm using a third party component, and it expects a prop to be a particular type.
I wish to use a different type.
Is there a way to override the type of a child component prop?
Or would I have to use a computed property and modify the prop in the parent component to the type the child component requires?
In general i think the best way would be to do as you proposed: To "use a computed property and modify the prop in the parent component to the type the child component requires". If you have to do so in several places, you could outsource the logic into a mixin that will be imported whenever the given third-party component is used.
If modifying the type of the property in the parent component isn't an option, the best way to fulfill your needs would be creating your own component that extends from the third party component and overriding the needed property. (https://v2.vuejs.org/v2/api/#extends)
Keep in mind however that the dependency containing the third-party might get updated over time. You should probably stick to a fixed version if following this approach.
I created a simple example on how to extend and override components (You can check it out as CodeSandbox here: https://codesandbox.io/s/qq9y7nm8n4
App.vue:
<template>
<div id="app">
<h2>ExtendedComponent: </h2>
<extended-component :message="1" />
<h2>BaseComponent: </h2>
<base-component message="This shall be a string" />
</div>
</template>
<script>
import ExtendedComponent from "./components/ExtendedComponent";
import BaseComponent from "./components/BaseComponent";
export default {
name: "App",
components: {
ExtendedComponent,
BaseComponent
}
};
</script>
BaseComponent.vue:
<template>
<div>
<h3>prop type: {{ typeof message }}</h3>
</div>
</template>
<script>
export default {
name: "BaseComponent",
props: {
message: {
type: String,
required: false
}
}
};
</script>
ExtendedComponent.vue:
<script>
import BaseComponent from "./BaseComponent";
export default {
name: "ExtendedComponent",
extends: BaseComponent,
props: {
message: {
type: Number,
required: false
}
}
};
</script>

Using v-model and refs in a slot in Vue2

I have a component that takes a main <slot> from a form that is generated elsewhere in my application. I'm trying to use v-model on the form inputs but my vue component just spits out a warning about the properties not being defined, when in fact they are.
I admit it's a weird way of doing things, but it seems to be the easiest way for me to do this since my form is being generated by Symfony.
html:
<my-component>
<input ref="start" v-model="start"/>
</my-component>
my component:
<script>
export default {
data() {
start: null
},
mounted() {
console.log(this.$refs) // === {}; expected {"start":{...}}
}
}
</script>
<template>
<div>
<slot/>
... other stuff here
</div>
</template>
console log:
Property or method "start" is not defined on the instance but referenced during render
I cannot use $refs or v-model in the html. Am I doing something wrong? Or is this just not possible.
If you declare v-model="start" in the parent then it belongs to the parent and needs to be declared there. It looks like instead you declare it in the component instead as null.
If you reorder things it should work as you expect:
Parent:
<parent>
<input v-model="start" :start="start"/>
</parent>
<script>
export default {
data() {
start: null // Important to define start here if it's used in this component's html
}
}
</script>
Component:
<template>
<div>
<slot/>
... other stuff here
</div>
</template>
<script>
export default {
props: ['start'], // Receive the prop from the parent
data() {
},
mounted () {
console.log(this.start) // Should echo the value of the prop from the parent
}
}
</script>