Computed properties on function instances - vue.js

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.

Related

reference vue instance in mapState function

Is there a way in Vue2 to do this:
....,
computed {
...mapState('myModule', {
myVal: (state, vm) => state.someVar.filter((_) => { return vm.someVar })
})
},
....
The actual function I'm working on is filtering the state.someVar in a more complex scenerio, so this is simplified. The point being that this is undefined.
Anyone know how to reference the vue in such a function?
The 2nd argument to the mapState function is supposed to be a state mapper (array or object)
If you are using an object (as you are), you can only set the properties of the object to the keys in your "myModule" state object. You cannot set them as functions
e.g {customName: moduleStateKey}
As for passing component instance, you can only do that in an action or mutation. However, that would make your store impure. It would be better to pass someVar to state via a mutation fired from the component, then use a getter for the filter logic and use the someVar passed to state there

what's the difference between declaring object inside data() and inside created() in VueJs

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()

What exactly does computed properties in vuejs?

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.

Vue.js: using a data object's method in inline event handler

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)

Mobx and observing array changes from third-party library

I have a class with #observable properties and can react to local observable changes OK. The class also makes use of a third-party library that has a method OrderBookSnapshot() which returns a snapshot of the most recent array, but is not observable. I gather that I cannot assign non-observable arrays to the observable property. But is there a way to observe non-observable arrays from another library without making that library observable itself?
export class MyOrderBook {
#observable
private offerBook: any[]
private cmeClient // third-party class
constructor(symbol: string[]) {
this.offerBook = []
this.cmeClient = new cmeClient.OrderBook(symbol[0])
}
// Calls third-party method and returns updated array
UpdateOrderbookSync() {
// This is not observable
this.offerBook = this.cmeClient.OrderBookSnapshot()
}
}
Adding potential solution to my answer. The #action.bound decorator appears to give the desired result. Though it is not clear if this is the best way to update an observable array, since most of the array is unchanged.
#action.bound
UpdateOrderbookSync() {
// This is not observable
this.offerBook = this.cmeClient.OrderBookSnapshot()
}