I use Laravel9 with Vuejs3.
I have a blade view that passes php variables to vue component:
<subscription-form
location="{{ $props['location'] }}"
orientation="{{ $props['orientation'] }}"
/>
In my main vue that receive data, I have the following code in script setup:
const initProps = defineProps(['location', 'orientation']);
const values = reactive(initProps);
This parent vue call a component like this:
<component
v-bind:is="steps[step]"
v-bind:formValues="values"
></component>
The problem is that my reactive variable values is not accessible for writing in my child vues.
I have the error
[Vue warn] Set operation on key "location" failed: target is readonly.
This happend when I do for exemple:
props.formValues.location = location;
It was working when I didn't have to pass php variable from my blade to the parent vue. But now I have data props at 2 levels from blade to main vue and then from main vue to child components, it is in readonly.
Help!
I tried to switch initProps or values variables from const type to var but it doesn't do anything.
I'm disappointed...
This was not working because of my defineProps() returning undefined
The problem was: THE CAPITAL LETTERS!
I changed <subscription-form :initPropsValues="{{ json_encode($props) }}"/>
to <subscription-form :initprops="{{ json_encode($props) }}"/>
And my defineProps() returns my object!
Why is that not working with caps?
Related
I'm trying to access to a method of an child component, to validate multiple forms.
I have an array named "forms", each form object has a randomly generated id. Based on these form objects I generate components and give them a ref name
In my validateAll method I'm trying to loop over all forms, find components with their id as component's ref name. When I find the component (no problem so far), I try to call the child's method. But I get an error.
This is where I render components with v-for loop:
<SupportRequestForm v-for="(form, idx) in forms" :key="form.id"
...
:ref="`formRef${form.id}`"
/>
This is validateAll method, where I try to access child method:
validateAllForms() {
return this.forms.find(form => {
const formComponent = this.$refs[`formRef${form.id}`]
console.log(formComponent)
return formComponent.validateForm()
})
}
And this is the error:
I can access child component's method when it's a static ref name but I can't do the same thing when the is generated on the spot. Is this an expected behaviour or am I doing something wrong ?
Thank you very much in advance.
No need to bind each form to the form id, just create one ref called forms and since it's used with v-for it will contain the forms array :
When ref is used together with v-for, the ref you get will be an array containing the child components mirroring the data source
<SupportRequestForm v-for="(form, idx) in forms" :key="form.id" ref="forms" />
in method :
validateAllForms() {
this.$refs.forms.forEach(formComponent=> {
formComponent.validateForm()
})
}
I recently updated laravel mix in my project to the latest and immediately I was swarmed by Vue errors. I seem to struggle with this one especially. I have a component:
<template>
<div>
<ChildComponent :context="this"></ChildComponent>
</div>
</template>
<script>
import ChildComponent from './child-component';
export default {
components: { ChildComponent },
...
}
</script>
This is the error I get: Error in render: "TypeError: Cannot read property 'context' of undefined".
Seems weird because in vue-devtools the parent component is present as an object in context prop of ChildComponent.
I should probably also add that context is defined as context: {} in ChildComponent's props.
this is not defined in the <template> and attempting to pass the entire Vue instance to the child seems like an anti-pattern. You should explicitly define and pass data and variables to children components, and (optionally) if you want to receive some data back from the child, you should emit events and bind to those events in the parent.
If you must access the parent component from the child, you can use this.$parent in the child component: https://v2.vuejs.org/v2/guide/components-edge-cases.html#Accessing-the-Parent-Component-Instance
But unless you have a good reason to reach for that $parent variable, it should be avoided as it tightly couples your components together.
I am new to Vue and after checking the docs I can not figure out how to achieve the following:
pass an arbitrarily named variable as a prop to a component instance.
From my understanding, props are meant to be a way to allow data to be passed to a component and as it states on the website:
Passing Data to Child Components with Props:
Props are custom attributes you can register on a component. When a value is passed to a prop attribute, it becomes a property on that component instance.
Since props can be required, it would seem that we can design components under the assumption that some data would be there, and possible within certain parameters (if the validator option is specified).
So I would like to define a function or object outside of vue, e.g. in an application, and pass this function or object to my vue instance.
This works if my named object of function has the exact same name as the prop to which I attempt to bind it. However, as I might have multiple instances of the Vue component and I might want to bind different data, I find using the same name for the variable less than ideal.
Now if I do as the Vue warning suggests, and name object / function the same as the prop, then the warning switches to that my data is not defined inside vue and to make sure it is reactive by reading: https://v2.vuejs.org/v2/guide/components-props.html
which, to be honest, doesnt really explain how to solve the issue,
or move the prop to the data level.
Which I can do (still gives the same warning), but kind of defeats the purpose of having props with my understanding of Vue.
This become more frustrating with anonymous vue instances.
e.g.
<script>
export default {
props: {
// records: {
// default: function(){return{}},
// type: Object
// }
},
data: function() {
return {
records: {} // define even an empty value in data for it to be 'reactive'
}
},
computed: {
fields: function() {
},
keys: function() {
return Object.keys(this.records)
}
},
methods: {
}
}
</script>
trying to use this as a component and set records to var myRecords = {"a": {}} fails:
<my-comp :records="myRecords"/>
So how exactly should I circumvent this? Where should I define my data then? and how should I handle the naming in the case of multiple instances?
A more fledged on example is found on a similar question:
Vue2: passing function as prop triggers warning that prop is already set
So I would like to define a function or object outside of vue, e.g. in an application, and pass this function or object to my vue instance.
It's hard to give a definitive answer because I don't know the specifics of how you have organized your code. Are you using Webpack? Single file components (.vue)? If yes to any of these, then you needn't use global variables in the way you have described in your question.
Your entire Vue app should consist of a single root Vue instance (which you instantiate with new Vue(...), and from there each component is rendered within the root component's template, and templates of those components, and so on.
Looking at the following template:
<my-comp :records="myRecords"/>
myRecords must be a property on the Vue component instance whose template contains the above. It could be declared within the data block, or as a computed property, or a prop, it doesn't matter.
Here's a small example:
<div id="app">
<my-comp :records="myRecords"></my-comp>
</div>
// Obtain records in some way and store it in a global variable
var records = ...
// This is the root Vue instance
new Vue({
el: '#app',
data: {
// You must store the records array in the Vue component like this
// for it to be referenced within the template.
// You can optionally transform the data first if you want.
myRecords: records.filter(r => r.name.startsWith('Bob'))
// ^ ^
// | |
// | +--- the global variable
// |
// +---- the name of the property on the component instance
}
})
Note that MyComp component does not access the records global variable in any way, it only takes its input through the records prop.
I see the about vue $ refs document, the console to see is {}, I do not know how to get the value of id?
There { } is no object, how to get $ refs id of value,but I think this {} not get to object.I try to use console.log(this.$refs.dataInfo.id) is undefined.
Look at the picture:
javascript file:
console.log(this.$refs)
HTML file:
<tab-item v-for="item in category" :id="item.id" ref="dataInfo">{{item.name}}</tab-item>
console.log(this.$refs.dataInfo.id) is undefined because you are trying to access an element's attribute through a reference to a component. Based on your example object, you can access it like this: this.$refs.dataInfo[0]['$el'].id
That's an odd way of doing it, I believe. The Vue way of doing it would be:
Using events. When props change in the child component and you want to do something about it in the parent component, you should emit a custom event. You'd do something like this in the child component: this.$emit('dataChange', data). And in the parent component add an event listener #dataChange="myMethod" to the component.
Using Vuex.
Having a good understanding of the basic concepts such as how the data flows in the application is a must and should not be overlooked!
I have a component called RpContainer which will receive data by its props called 'completeReport' like that :
export default {
props: ['completeReport'],
created() {
}
}
This component is used in my main Vue called Report like that :
<RpContainer v-if="displayReport == true" :completeReport="indicatorList"></RpContainer>
In my main Vue, I'm doing some API calls to get some data, with those data, I built an array (indicatorList). And what I want is to link this array once it's completly done (there is a delay between my call and the answer) with my props 'completeReport'.
But the problem is that when my component RpContainer is created, my array is still empty. So how could I link it properly to have an update in my component when my array is succesfully build.
I tried to put a watcher my props but it's not working..
Can you help me ? Thanks