According to Vue docs, binding a key is required to use custom components in a v-for:
<template v-for="(task,i) in tasks">
<task-card v-bind:task="task" v-bind:key="i"></task-card>
</template>
I would like to use that key in the child component (task-card), but neither using this.key or adding key as a prop (is a reserved Vue keyword) works. Is there a way of doing this without passing yet another prop with the value "i"? Currently working with "vue": "^2.5.9".
If you want to pass data to the child, you should be using props (key is reserved so you'll have to name it something else).
Otherwise you can access the key on the vnode within the component via this.$vnode.key.
Vue 3
For Vue 3 the API has changed. You will need to access the vnode from internal private instance like so: this.$.vnode.key. As far as I know this is undocumented and may change; use with caution.
Related
I need to know the correct usage and the best practice of the setup function provided by vue3's Composition API.
I checked in my current project where developers actually use the setup function instead of creating the component with the traditional approach.
If it is just a design principle or improvement something then where we should apply these. I read the official documentation but instead, they didn't explain the concept, they just provided the list of arguments available in this function.
MyBook.vue
<template>
<span>Warning:- {{warning}}</span>
<button #click="warning = !warning">toggle</button>
</template>
<script>
import { ref } from 'vue'
export default {
props: ['warning'],
setup(props, context) {
const warning = ref(props.warning)
return {
warning,
}
},
}
</script>
<MyBook
:warning="true"
/>
As you can see above, I can't use the same name of a property to data attribute for a component but in the case of setup, we can do this and update the value. (as property should not change within component).
The Vue devtool is also showing the setup as a different category.
setup sets up an instance and returns properties that it should have. The purpose of Composition API, which setup is a part of, is to replace Options API, where an instance is determined by component options. So setup is the replacement for data, methods, computed, watch and lifecycle hooks.
As the reference explains, setup also replaces beforeCreate and created lifecycle hooks, the rest of hooks are set inside of it.
There is no conflict between data and props in setup function because props is accessible as setup parameter, i.e. warning and props.warning are accessible at the same time. In a template, they aren't and shouldn't be distinguished, they instance properties, the solution is to not allow name conflicts. They have been previously available with $data.warning and $props.warning magic keywords but their use wasn't encouraged. If warning value differs from a prop of the same name, and both should be available in a template, it should have a different name.
I have a page which is being generated by my app in java (SSR) depending on some data (e.g. a publisher for some entity). I would like to create some sort of a reusable Vue component that would call an API method and request some data about the entity that is currently opened. Also in some cases there could be more than one such component on one page.
The only thing I cannot really figure out being a most-of-the-time backend developer - is how to tell a component which entity I'm trying to get. The only solution that comes to my mind is to generate the parent <div class="my-vue-component"><div> with an additional attribute, e.g. <div class="my-vue-component" publisher-id="123"><div>.
But I cannot find if there is a way to access that attribute from inside the Vue instance. (Please note that I don't have a fixed id for this div as there can be many such components on the same page referring to different data).
Any kind of advice is appreciated.
As stated in the previous answer, you will need to use props. Although since you will pass down data to multiple components and the data can change, there should be a way to respond to those changes.
For that, you will have to bind the prop with a reactive variable in your page/parent component.
So your SSR code should look like
<my-vue-component :publisher-id="openId"></blog-post>
And inside your page/parent component will reside the openId, which you can change as needed, and your component will re-render if prop passed to it changes.
export default {
data(){
return {
openId:1
}
}
}
It seems like you are looking for components-props.
You can define a prop like
Vue.component('blog-post', {
// camelCase in JavaScript
props: ['postTitle'],
Your SSR code should then be generating:
<!-- kebab-case in HTML -->
<blog-post post-title="hello!"></blog-post>
Inside the component methods you can access the passed in value using this.postTitle
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!
So i have some object with posts, and i'm using v-for to iterate them in the custom component, but how to pass data from this object to this component, loop is a one thing displaying data i another...
<app-single-post v-for="post in posts" postData="$post"></app-single-post>
This is my component declaration. Do i need also some kind of special prop setup? Have the same error, again and again:
Property or method "postData" is not defined
Use the binding syntax.
<app-single-post v-for="post in posts" :post="post" :key="post.id"></app-single-post>
Camel-cased properties need to be converted to kebab-case when they are used as attributes. Also, I added a key. You should always use a key when you use v-for and it is required when you iterate over a custom component. Ideally you would want to use a post.id if one is available.
In your component, you should have a property defined like this:
export default {
props:["post"],
methods: {...},
etc.
}
To reference the post in your component template you can use
{{post.id}}
and inside methods it would be
this.post