I am passing an object like this into a component:
obj = {
prop1: 1,
prop2: 2,
prop3: 3
}
<my-component :data="obj"></my-component>
the component only has these two defined, by design, because I want to ignore what is not defined:
props: {
prop1: Number,
prop2: Number
}
what's happening is when the component is rendered, the root node looks like this with the undefined prop placed like an attribute?!:
<div prop3="3">
...
</div>
I don't want undefined props to be de-structured by the component and definitely don't want them to rendered in the root element. I want them to be ignored. Is there a flag or some setting to say ignore all undefined props?
Please don't say why I would ever need this. I do because these objects are built somewhere else and don't want to create new subset objects just for this purpose.
You can use:
props: {
prop1: Number,
prop2: Number
},
inheritAttrs: false
This will tell Vue to not add additional props to the element as attribute but those props will instead be stored in $attrs, so you could access your prop using this.$attrs.prop3
See https://vuejs.org/guide/components/attrs.html#disabling-attribute-inheritance
Related
I have a model name defined in my Component tag as seen below:
<b-table-column v-if="" field="columnName" v-slot="itemProps">
<SelectableAttribute
:attr-name="props2.row.fieldClass"
:attr-id="itemProps.row.id"
:model-id="props.row.id"
:model-name="NewParticipant"
>
However I receive this error:
[Vue warn]: Property or method "NewParticipant" is not defined on the instance but referenced during render. Make sure that this property is reactive, either in the data option, or for class-based components, by initializing the property.
I'm not quite sure how I'm meant to define a model-name, in my props I assume but where? I've attached code below.
export default {
props: {
participants:
{
type: Array,
default: null
},
},
components: {
SelectableAttribute
},
As your error tells you, NewParticipant is not defined. You need to add it to your component as a property in data(), like this:
data() {
return {
NewParticipant: [] // Array for example
}
}
Or else, if you want your prop participants to be the model-name, you need to change it to :model-name="participants".
Slall question:
I have a 2 parent components nesting the same child component inside of them.
I use props so the parents can tell the child what title to show.
this child component is a photo gallery. It makes a query to the database, download photos and show them up. classic.
I need the parents to tell the child where to get the photos from:
Get the photos from All users, for the home page
or
get only the photos from a specific user for a user's page.
I'm wondering if I can pass this information through a prop.
Is that possible? Can we use the info from a prop as a varialble inside of the setup() function?
Is there a better way to do this?
Passing objects from one component to a child component is the purpose of props.
You can pass many items through props. VueJS has the following types built-in:
String
Number
Boolean
Array
Object
Function
Promise
In the V3 VueJS guide it gives the following example of a prop being passed into a component and then being logged to the console inside the setup() method.
export default {
props: {
title: String
},
setup(props) {
console.log(props.title)
}
}
However, when using props, you should always mark whether the is required, what its type is and what the default is if it is not required.
For example:
export default {
props: {
title: String, // This is the type
required: false, // If the prop is required
default: () => 'defaultText' // Default needed if required false
},
setup(props) {
console.log(props.title)
}
}
It's important to note that when using default, the value must be returned from a function. You cannot pass a default value directly.
I have a vue date component that is composed of a vue-flatpickr-component. When I pass config options in as props, of course, they work as expected, however, if want to change one of the config options which should be possible, it won't propagate down. I'm not a Vue guru, any advice would be helpful.
I'm using a page component in a Laravel app, it shouldn't be relevant, however, just in case someone answers with vuex or vue-router, those won't work here.
Here are the form elements in play from page.vue:
<material-select
name="specialist"
label="Specialist"
default-text="CHOOSE HOMEVISIT SPECIALIST"
:options="staffMembers"
v-model="form.specialist"
:validation-error="form.errors.first('specialist')"
class="mb-4"
></material-select>
<div class="w-1/2">
<material-date
label="Appointment date"
name="appointment_date"
v-model="form.appointment_date"
:validation-error="form.errors.first('appointment_date')"
class="mb-4"
:external-options="{
enable: this.appointmentDates,
}"
></material-date>
<pre>{{ this.appointmentDates }}</pre>
</div>
Here is the computed property driving the config change:
computed: {
appointmentDates(){
if(this.form.specialist !== null){
return this.availableDates[this.form.specialist - 1]
}
return []
},
When a different home visit specialist is chosen, it will update with Vue's reactivity.
I have a computed property changing the config options. Here are the props data and the relevant computed property from the MaterialDate.vue file:
import flatPickr from 'vue-flatpickr-component';
import 'flatpickr/dist/flatpickr.css';
export default {
components: {
flatPickr
},
props: {
value: String,
label: String,
validationError: String,
name: {required:true},
optional: {
default: false
},
externalOptions: {}
},
data() {
return {
defaults: {disableMobile: true,},
options: this.externalOptions
}
},
computed: {
config(){
return Object.assign({}, this.defaults, this.options)
},
This will of course never update the enabled dates option because the prop is immutable, I need to get access to the set(option, value) section of the wrapped by vue-flatpickr-component. However, my Vue kungfu is not really strong enough to source dive it to see how I might access it and programatically call set('enabled', [new dates]).
Sometimes, you shouldn't code when you are tired :) But Hopefully this will help someone at some point. I was over thinking this. Data is passed down through props, and if controlling data changes it has to be reflected in the propagated data. Much like v-model with it's value prop.
So instead of binding the config object on this.options which doesn't stay hooked to it's prop value that it was initialized from, the computed function should be calculated from the prop which will change based on the new passed in options prop.
so simply change the computed function to:
computed: {
config(){
return Object.assign({}, this.defaults, this. externalOptions)
},
and remove the data element.
... Elementary
Sorry for the cheese it's late and I feel relieved.
Currently I have a vue-multiselect component which requires a v-model.
I want to wrap this component so that I can build one single-select component and one multi-select component.
While working on the single select component I encountered the following warning
[Vue warn]: Avoid mutating a prop directly since the value will be overwritten whenever the parent component re-renders. Instead, use a data or computed property based on the prop's value. Prop being mutated: "model"
They are right but in my case I really need to change the value from the parent (like I replace my single-select code with the vue-multiselect code) component and I also do not want this warning.
Here is the code for my component:
Vue.component('single-select', {
props: {
model: {
required: true
}
}
template: '<multiselect\n' +
' v-model="model"\n' +
...>\n' +
...
'</multiselect>'
});
One solution would be to pass a function as a model parameter and return the field from the parent but I really hope for a better solution.
Vue has a shortcut for 2 way binding called .sync modifier.
How it works in your case:
add .sync when you pass model as prop
<single-select :model.sync="..."></single-select>
emit an update:model in the child's input event
Vue.component('single-select', {
props: {
model: {
required: true
}
},
template: `<multiselect :value="model" #input="$emit('update:model', $event)"> </multiselect>`
});
Just give the internal model reference a different name, and the in the Vue component's data function map it manually:
Vue.component('single-select', {
props: {
model: {
required: true
}
},
data: function() {
return {
singleSelectModel: this.model
};
}
template: '<multiselect v-model="singleSelectModel"></multiselect>';
});
This is of course, assuming that you do not want to mutate the parent data, but simply making a copy of model and giving the child component the freedom to change it whenever it wants.
If what you want is to also update the parent data from the child, you will have to look into emitting events from the child and listening in the parent.
I am creating a component and want to pass two properties (item & brokerageID) to the component. Here is the HTML code:
{{brokerageID}}
<holiday-component v-bind:item="item" v-bind:brokerageID="brokerageID" testID="45" ></holiday-component>
Here is the code for 'holiday-component'
Vue.component('holiday-component', {
props: ['item',
'brokerageID',
'testID',
],
data () {
return {
holidaysData: [],
showHolidays: false,
}
},
methods: {
getHolidays(contactID) {
....
},
template: <div> {{testID}} {{item.contactName}} {{brokerageID}}
....
The 'item' property is getting passed to the component (item.contactName is displayed correctly in the component template. However, somehow, brokerageID (property of the Vue object) is not getting passed. This property exists which is confirmed as {{brokerageID}} used above the component in HTML displays value. But, within the component template, brokerageID is not available. Also, the testID property passed to the component is not displayed.
Could someone please advise, what is wrong in my implementation that I am unable to use brokerageID in my component?
See Vue's docs about prop naming https://v2.vuejs.org/v2/guide/components.html#camelCase-vs-kebab-case
In this instance, using v-bind:brokerage-id and v-bind:test-id should do the trick.