Is it possible to pass a reactive property in VueJS? - vue.js

There is a code I take over from another developer. He used a Vuex property POLL to initialize some components. I wanted to use a different approach - get the object at upper level and pass it as a property downstream to the components. The object is fetched in async method from the backend. I thought that Vue reactivity will initialize real value later. But I get an error:
[Vue warn]: Property or method "poll" 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. See: https://v2.vuejs.org/v2/guide/reactivity.html#Declaring-Reactive-Properties.
found in
---> <PollHeading> at src/components/molecules/PollHeading.vue
<CompletePoll> at src/components/organisms/CompletePoll.vue
<Home> at src/views/Home.vue
Home.vue
<Poll v-if="this.$store.getters.LATEST_POLL" :item="this.$store.getters.LATEST_POLL" />
...
created() {
this.$store.dispatch('GET_LATEST_POLL');
},
CompletePoll.vue
<PollHeading :item="item"/>
...
props: {
item: Object,
},
PollHeading.vue
props: {
item: Object,
},
Am I going the wrong direction and the original developer was right? Or is there a way how to fix my approach? He used to do:
PollHeading.vue (I renamed to CompletePoll.vue)
computed: {
poll() {
return {
poll: this.$store.getters.POLL,
};
},

Problem 1)
[Vue warn]: Property or method "poll" is not defined on the instance but referenced during render. means that you have this declared in template block of .vue file, but it's not declared in the script's data property or computed. I don't see that specific .vue file where you use poll variable.
Problem 2) When you use variables in tmeplate blocks, you shouldn't use this .
So instead of this: <Poll v-if="this.$store.getters.LATEST_POLL" :item="this.$store.getters.LATEST_POLL" />
Write: <Poll v-if="$store.getters.LATEST_POLL" :item="$store.getters.LATEST_POLL" />
Problem 3) https://github.com/literakl/mezinamiridici/blob/master/spa/src/components/molecules/PollHeading.vue on this file you use poll in template but you don't have that variable created anywhere. your prop's name is item and not poll. So change poll to item in template block everywhere in that file.

Related

Preferred way to access props in Vue Single File Component

Suppose I have a prop named message which I want to access from the script section of a .vue file.
I know that it can be accessed using this.$props.message and this.message from the data function.
Which is the preferred way to access props from different lifecycle hooks (created, mounted, etc), and from computed getters, and methods?
Component properties as well as passed in props should always be referenced to by this.propName, because you shouldn't assign a component property with the same name as a passed in prop. In this case Vue will respond with an error.
As Aer0 said, they shouldn't have the same names:
props: ['propMessage'],
data() {
return {
message: ''
};
},
created() {
console.log(this.propMessage);
console.log(this.message);
}

Vue.js: property or method is not defined on the instance, but it is

I have a Vue.js component that looks like this:
<!-- MyComponent.vue -->
<script>
export default {
render: () {
return;
},
methods: {
foo() {
alert('hi');
},
},
};
</script>
And then my HTML looks like this:
<my-component #click="foo" />
When I run this I get an error:
Property or method "foo" 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 can't seem to understand what I'm doing wrong here -- all the other SO questions about this error seem to be caused by scoping issues, but I'm just dealing with a simple component.
foo would need to be defined in the component using my-component, not in my-component itself.
Also, you'd need to do #click.native, unless you're specifically $emiting an event called click in my-component.
If you were to use #click="foo" inside of this component on an html element it would work like you expect (a #click on a component needs .native).

Difference in Vue between data() and adding data in created()

Is there a difference between the following? I've seen examples doing both and am unsure why you would choose one over the other.
Vue.component('test', {
data() {
return { myDataA: 10 };
}
//vs
created() {
this.myDataB = 10;
}
}
Variables set in created() on this will not be reactive. In order for them to be reactive, you must define them in the object returned by data().
Example (note how the text does not change in the output):
https://jsfiddle.net/oyf4quyL/
in a component, there are three places where you can define you data:
data properties
computed properties
props
the created property is lifecycle hook in Vue. what this means, is that the Vue will run this function when the component is created. there are also other lifecycle hooks in Vue you can use, like mounted or beforeMount or beforeCreate and etc.
now with this in mind, let's answer your question.
when you define myDataA in data property, Vue will automatically create some "watchers" for this data property, so anytime that you set a new value to myDataA, anywhere that is using it, will be called again. but when you define a property directly on Vue instance (this), you will lose this "watchers" feature. (which by the way is just some getters and setters!)
so as i said, the best way and the correct way to define a data property is on any of the three places that i mentioned, based on your need. (because each of them has different use-cases that the others).

How know if Object passed by prop is changed in Vuejs

How can i know if my object retrivied by props is changed or not?
Example.
I have an object passed by props like:
object:{
id: 1,
list: [{..},{..}],
propertyExample: true,
message: "I know that You will change this input"
}
And in my html frontend I have an input that change value of message or another property like:
<input type="text" v-model="object.message" />
And I would notify when my "entire original object" (that passed by prop) is changed. If I use watch deep the problem As documentation says is:
Note: when mutating (rather than replacing) an Object or an Array, the
old value will be the same as new value because they reference the
same Object/Array. Vue doesn’t keep a copy of the pre-mutate value.
So I have an object retrieved by props, so I should "disable" save button if object is equals to "original" or "enable" if object is different so if I make an update in frontend like modify property.
so If I enter in a page with my component I have original object like above described, and my save button is disabled because the "object" is not changed.
I would enable my save button if I change one of the properties of my object.
so example if I add a object in a property list array described, or if I change property message, or if I add a new property.
Watch function will be called when one of property in props object has been changed.
You can also use "v-bind" to pass all the properties of the object as props:
so
<demo v-bind="object"></demo>
will be equivalent to
<demo :id="object.id" :list="object.list" :propertyExample:"object.propertyExample" :message="object.message"></demo>
Then you can watch message prop individually for changes.
Edit
You can also use Vue Instance Properties.
There may be data/utilities you’d like to use in many components, but you don’t want to pollute the global scope. In these cases, you can make them available to each Vue instance by defining them on the prototype:
Vue.prototype.$appName = 'My App'
Now $appName is available on all Vue instances, even before creation. If we run:
new Vue({
beforeCreate: function () {
console.log(this.$appName)
}
})
Add watcher to that passed prop. and do something when changed.
watch: {
passedProp(changedObject) {
//do something...
change the variable which stands for enabling the "SAVE" button
}
}
OR if you are not using webpack/babel
watch: {
passedProp: function(changedObject) {
//do something...
change the variable which stands for enabling the "SAVE" button
}
}

What is the best way to specify data with brackets in Vuejs?

I've a page where field names are of type array.
eg. mapping[map][email_address][type]
Now in Vue, I want to set the default value and I'm doing it as below
new Vue({
el: '#configure',
data: {
mapping: {
map: {
email_address: {
type: 'incoming_field'
}
}
}
}
})
But I get an error in console
[Vue warn]: Property or method "map" is not defined on the instance but referenced during render. Make sure to declare reactive data properties in the data option.
vue.js:569 [Vue warn]: Property or method "email_address" is not defined on the instance but referenced during render. Make sure to declare reactive data properties in the data option.
vue.js:569 [Vue warn]: Error in render function:
(found in <Root>)
What is the best way to handle such field names in Vuejs?
As par you code, you have to do:
mapping['map']['email_address']['type']
or
mapping.map.email_address.type
You should rethink your data to not have so many nested objects.
If you are setting a property directly within an object, it is good practice to use Vue.set to ensure you do not break reactivity. Doing this will save you hours of headaches trying to figure out where something broke.
Vue.set(mapping.map.email_address, 'type', value_to_set)