There are couple of questions related computed properties like the following
"vuejs form computed property"
"Computed properties in VueJs"
"computed property in VueJS"
"Use computed property in data in Vuejs"
They are asking about specific error or logic. There are lot of websites that are explaining about vuejs related concepts. I read about computed properties on vuejs official website. When we do complex calculations or want to avoid to write more logic in our html template then we use computed properties.
But could not get any solid understanding about computed properties, when it calls, how it calls, what exactly do?
TL;DR: Computed properties are getters/setters in Vue.
When defined in the shorthand form, they are getters:
computed: {
someComputed() {
return `${this.foo} ${this.bar}`;
}
}
is equivalent with
computed: {
someComputed: {
get: function() {
return `${this.foo} ${this.bar}`;
}
}
}
which can also have a setter:
computed: {
someComputed: {
get: function() {
return `${this.foo} ${this.bar}`;
}
set: function(fooBar) {
const fooBarArr = fooBar.split(' ');
this.foo = fooBarArr[0];
this.bar = fooBarArr[1];
}
}
}
In short, Vue computed properties allow you to bind an instance property to
a getter: function run when you look up that property; usage:
this.someComputed // returns the computed current value, running the getter.
a setter: function run when you attempt to assign that property; usage:
this.someComputed = value; // sets the computed current value, running the setter.
Read more on getters and setters in Javascript.
And here's the documentation on Vue computed properties.
You can use computed properties when for example you have some logic what will blow up your template.
The idea is, that normally you want to keep all javascript logic in the javascript side of your vue component, and only access final data in your data (if possible)
For that you can use computed props, which normally are doing simple things like:
computed: {
// a computed getter
reversedMessage: function () {
// `this` points to the vm instance
return this.message.split('').reverse().join('')
}
}
Or an another good example if you have some currency and you want to format it with thousand separator and euro ign at the end.
Then you can access your computed prop in the template like you access a normal prop, you dont have to call it as a function.
like so:
<div>{{reversedMesage}}</div>
Every time, when any variable what is used in your conputed prop is changing, vue vill take care of it and will re-calculate your computed property again.
Lets say you have the following:
computed: {
prettyAmount: function () {
return this.amount + ' ' + this.currency.toUpperCase()
}
}
<div>{{prettyAmount}}</div>
Whenever currency or amount changes, the output of prettyAmount will be changed as well.
Related
I want to know what is the difference in VueJs between these two types of declaration :
data() {
return {
foo = 'bar'
}
}
and this :
created() {
this.foo = 'bar'
}
I know that I an access both using 'this' in or in methods.
Also, if the returned object in data() is saved in "memory" of the component, where does the object declared in created() is saved? are they in different scopes?
Also, I know that to fetch data, the fetcher lands in created() and then updates the data object, but this question is specifically about the differences between the two ways of declarations i mentioned
Is there any differences in the background?
You can read more about vue data here.
Vue will recursively convert its ($data) properties into getter/setters to make it “reactive”..
created() {
this.foo = 'bar'
}
Declaring like above, you won't be able to watch the attributes.
You can check this example out, watch function isn't fired with the attribute being not defined in data()
I would like to understand when you can use a computed property like this:
computed: {
selectedDate () {
return this.$store.getters['stockProposal/getDateEndArticle']
}
}
Where the getter is defined as follows:
getDateEndArticle: state => {
return state.articleSettings['date_end']
}
Where in the template I then use:
v-model="selectedDate"
Sometimes this works for me, but often I get the following error 'Property or method "selectedDate" is not defined on the instance but referenced during render.'
Can someone explain to me why this is not always working?
I also tried to follow this tutorial: https://itnext.io/anyway-this-is-how-to-use-v-model-with-vuex-computed-setter-in-action-320eb682c976. But even with a computed setter added, I still get the same error. While I am doing exactly this: https://vuex.vuejs.org/guide/forms.html#two-way-computed-property.
I have a Vue(2.5+) component where I'm setting a data property to a new Foo object. Using foo.bar() in the click handler calls the method correctly, but throws Uncaught TypeError: cannot set property 'someVariable' of null when trying to modify properties inside the Foo class. Setting it up so that Foo is an object literal instead of a class also does not resolve the error.
I suspect something weird is happening with this, between the component and the class?
Vue component
import Foo from './foo.js'
export default {
template: `<div #click="foo.bar"></div>`,
data() {
return {
foo: new Foo()
}
},
created() {
console.log(foo); // foo is not null here
}
}
Foo class
export default class Foo
{
constructor()
{
this.someVariable = 0;
}
bar(e)
{
// modify this.someVariable
}
}
but if I change the vue component to reference the external method through it's own "methods" property, it works.
Vue component (working)
import Foo from './foo.js'
export default {
template: `<div #click="bar"></div>`,
data() {
return {
foo: new Foo()
}
},
methods: {
bar(e) {
this.foo.bar(e);
}
}
}
As said in the comments, foo.bar without any context attached to it :
In JS functions are objects, just like any object they have their own this "pointer".
In the evaluation of their body, this is bound to a specific object referred to as context which is either the default context (automatically set) or user defined (manually set).
Inheritance in JS is achieved through a prototype chain and methods should be defined on/attached to the class's prototype. Because of this, when you call foo.bar() :
You are in a method call context, therefore foo will be bound to the method
bar is searched on the object first then in the prototype chain
But methods behave just like any other property : when you do foo.bar you get a reference to the actual method which is an unbound function (default behavior for methods, since it is bound when called on an object).
Therefore, what you really need to do in this situation is foo.bar.bind(foo).
I would also suggest taking a quick look into this ES6 proposal for a bind operator and its implementation as a Babel plugin which allows nice things like passing ::foo.bar instead of foo.bar.bind(foo)
I'm not new to Vue.js, but I'm going through the docs again, trying to pick up on anything I missed the first time. I came across this statement in basic example section of using computed properties:
You can data-bind to computed properties in templates just like a normal property. Vue is aware that vm.reversedMessage depends on vm.message, so it will update any bindings that depend on vm.reversedMessage when vm.message changes. And the best part is that we’ve created this dependency relationship declaratively: the computed getter function has no side effects, which makes it easier to test and understand.
The part about we’ve created this dependency relationship declaratively: the computed getter function has no side effects, isn't clear to me. I do understand that a side effect is some action happening that is not directly related to the pure intentions of the function, but I'm not clear how it's being used in this statement.
Could someone explain further what the opposite could be? What are the potential side effects that could be happening?
The term side effect here refers to any data mutations performed in the computed property getter. For example:
export default {
data() {
return {
firstName: 'john',
lastName: 'doe',
array: [1,2,3]
}
},
computed: {
fullName() {
this.firstName = 'jane'; // SIDE EFFECT - mutates a data property
return `${this.firstName} ${this.lastName}`
},
reversedArray() {
return this.array.reverse(); // SIDE EFFECT - mutates a data property
}
}
}
Notice how fullName mutates firstName, and reversedArray mutates array. If using ESLint (e.g., from Vue CLI generated project), you'd see a warning:
[eslint] Unexpected side effect in "fullName" computed property. (vue/no-side-effects-in-computed-properties)
[eslint] Unexpected side effect in "reversedArray" computed property. (vue/no-side-effects-in-computed-properties)
demo
In knockout.js I was able to do the following:
function Person() {
this.firstName = ko.observable('Foo')
this.lastName = ko.observable('Bar')
this.fullName = ko.pureComputed(() => {
return this.firstName() + this.lastName()
})
}
var p = new Person()
console.log(p.fullName()) // FooBar
Is there any way to add reactive computed properties on objects which are not a component data in Vue?
In Vue, you do not need to explicitly declare reactive properties and methods like Knockout requires. Everything is just a plain object.
What actually makes the object reactive in Vue is when you assign it to a component through a property that was declared in the data object of that component.
So your example in Vue would just be:
function Person() {
this.firstName = 'Foo';
this.lastName = 'Bar';
this.fullName = function () {
return this.firstName + this.lastName;
};
}
var p = new Person();
console.log(p.fullName()); // FooBar
If you use it inside a component, then it will be reactive, like this:
const comp = new Vue({
template: '<div>{{ person.fullName() }}</div>',
data: {
person: null,
},
});
// Vue detects that p is being assigned to the reactive property
// 'person' and makes p reactive.
comp.person = p;
I should mention, I'm not really sure what you mean by "which are not a component data in Vue" because the whole reason why you want something to be reactive in the first place is because you want it to be rendered in a component's template and for the component to re-render automatically when a property changes, so you can't really make something reactive externally to Vue.
I understood your question as along the lines of "how do I make something reactive to Vue without needing to specify it directly within a Vue component's data or computed properties?". Keep in mind that the person property must be declared upfront in the component's data for that property (and any data assigned to it) to be reactive. As long as you do that, then you can design your model objects however you want.