For example {{ window }} template gives out a [Vue warn]: Property or method "window" is not defined
Is this intended behaviour? If I understand correctly adding window to the Vue data would be a bad idea.
Yes, this is intended behaviour. The Template is "scoped" to the component instance, and there are only a few exceptions made - {{ Math.random() }} works, for example.
The window object as the global object is not something templates should directly interact with.
If you need to, use a method to get what you need.
Related
So in Vue, you can pass props between components by writing v-bind="$attrs". Then, you can use these props by saying, for instance {{ this.$attrs.somePropsHere }}. It would be ideal if I can get suggestions as soon as I start typing this.$attrs., as it always is with Intellisense. But unfortunately I can't. Any ideas on how to make this work, if such a functionality exists?
I thought that two way data flow was not just discouraged but impossible between parent and child components in Vue.js. However I've discovered it's actually possible using a custom class as a prop.
Custom class:
class MyClass {
constructor(val) {
this.val = val;
}
}
Parent template:
<div>
<child :obj="obj"></child>
</div>
Child props:
props: {
obj: MyClass
}
Child template:
<div>
<button #click='obj.val="changed"'>Change val</button>
</div>
Here is a working example: https://codepen.io/francoisgaudin/pen/XWdBOxN
So now I'm wondering why this is possible - is it deliberately allowed or is it a loophole that should not be exploited??
I found the answer in Vue.js documentation on the "one way data flow" (https://v2.vuejs.org/v2/guide/components-props.html#One-Way-Data-Flow). They specify the following caveat:
Note that objects and arrays in JavaScript are passed by reference, so
if the prop is an array or object, mutating the object or array itself
inside the child component will affect parent state.
So one way data flow is not strictly enforced and there is no error or warning in this case. This is a loophole - (which is best avoided).
You're able to modify the object because object references are values in Javascript - which makes objects act like they are passed by reference.
In other words:
Javascript always passes by value, but for arrays and objects the value is a reference to the object.
https://medium.com/nodesimplified/javascript-pass-by-value-and-pass-by-reference-in-javascript-fcf10305aa9c
It's allowed because the alternative is copying the whole object (which could include nested objects and is not really practical).
Also, this is an opinion, but you should not do this.
I do not see a downside of using it, more than loosing the track where the object is modified in a very nested child components. I will play around a bit more with your codepen, I also wanna know why it is possible, and Avoid mutating a prop directly error is not raised.
you can use Vue's $emit feature to communicate between child/parent, more examples here :
https://v2.vuejs.org/v2/guide/components-custom-events.html
So this was largely a test. In normal Vue, you'd get the line number of where the error went wrong, but it seems like Nuxt is quite general about that, and just tells you the file only, without the line number. Is it possible to add it back in with some settings?
I just have a simple page set up:
pages/example.vue
<template>
<div>
I am example {{ something }}
<nuxt-child/>
</div>
</template>
warning:
[Vue warn]: Property or method "something" 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
---> <Pages/example.vue> at pages/example.vue
<Nuxt>
<Layouts/default.vue> at layouts/default.vue
<Root>
It's not possible to get the line number from this warning message.
The Vue template compiler does not generate source maps, so it would be impossible to get the original line number.
Looks like it is planned for v3, though.
The standard way of passing properties to a component is to use the v-bind directive:
<Child :prop1="myObj.prop1" :prop2="myObj.prop2" :prop3="myObj.prop3"/>
But Vue makes it possible to simply pass the entire object:
<Child v-bind="myObj"/>
However, one downside I've come across is that the HTML element shows all these properties:
<div class="child" prop1="[Object object]" prop2="2" prop3="[1,2,3]">...<div/>
Is there a way to prevent this behaviour?
There is a way to avoid this without passing props explicitly:
https://v2.vuejs.org/v2/guide/components-props.html#Non-Prop-Attributes
add inheritAttrs: false to the component you are passing props to
After reading documentation on component props look's like vueJs does not provided such provision to avoid this. https://v2.vuejs.org/v2/guide/components-props.html
I am trying to pass down a initial value to a select input bound by v-model. I cannot figure out why this doesn't work:
props: ['team'],
data() {
form: {
data: {
country: this.team.country
}
}
}
The form.data.country is undefined. Although, the props data is actually passed down. I can access it with Vue Devtools like $vm0.team.country and I can print other data from the props. However, it is not registred in the data().
Also, when trying to debug using mounted(), the property, team, is not defined.
mounted() {
console.log(this.team);
}
But, as I stated earlier, it is defined when the template is rendered, and can be used like this.
<input class="input" type="text" name="name" :value="team.name" disabled>
Why is the properties I am passing not beinged recognized in data()?
The asynchronous loading is not the problem. Even if team is hardcoded above, it's still undefined when data is created in the component. (The component needs to be created before the root Vue that passes the prop.)
There is, perhaps someone will correct me, never a good reason to reference props in your data. Something is either data (the current component knows where to find what it wants) or it's a prop (the component will let it's context supply the info).
Then, as you've discovered, your data is created once. Vue watches everything for changes, but you're vulnerable to changes of the root value. If the thing referenced as a value when data is created, changes, the reactive pipe is broken. The answer to this is the store pattern. You watch a variable in global scope, that never gets replaced, even though it's contents may change.
code
The props data was asynced loaded by the parent. This was suggested in a comment by #Bert