Map Vuex getter to a computed property AFTER component is created - javascript

Is it even possible?
I know I can do it like this:
computed: {
...mapGetters({
xyz: 'xyz'
}),
but I was wondering if I can do it using inherited mapGetters, i.e. in created hook:
created () {
this.$options.computed = Object.assign(this.$options.computed, {...this.dependencies.mapGetters(this.stores)});
console.log(this.$options.computed); // returns mapped getters
},
Console output returns mapped getters, but it doesn't seem to work, in Vue DevTools those Vuex bindings are undefined.

No. You can't. There's no way around.
Also,
The $options is read only.

Related

How to access mapState property inside the method

How can I access the count property inside the method when I use vuex? Please see my code below.
Code screenshot:
Error
[Vue warn]: Computed property "count" was assigned to but it has no setter.
You can access computed properties just like you access your data properties in a component. But since you are mapping the state in this case. You should not increment or alter its value directly inside the component. Instead, you should dispatch an action with the updated/incremented value and use mutation to mutate the value of the count property in the state object.
More detail https://vuex.vuejs.org/guide/mutations.html#commit-with-payload
The mapState you wrote is inside a computed block. By default computed values are read-only, but you can make them read/write by giving them a setter (ie a function to call when modifying the computed value):
computed: {
count: {
get() { return this.$store.state.count; },
set(newValue) {
// This will most likely throw a warning, as it is bad practise.
this.$store.state.count = newValue;
}
}
}
https://v2.vuejs.org/v2/guide/computed.html#Computed-Setter

What is the correct way to access Vuex getters from Cypress?

I have a getter called viewItems in my Vuex store, returning an array.
I can access it from my Cypress test with:
Cypress.Commands.add("getStore", () => {
return cy.window().its("app.$store");
});
cy.getStore().its("getters.viewItems.length").should("equal", 13);
It works, but I get an error on the console when running Cypress:
[Vue warn]: Property or method "nodeType" 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
Is there a better way to access getters, or is it something else?

Vue using v-for to render computed properties after loaded

I'm using v-for to iterate over a computed property, and that computed property depends on a data attribute, which is initiated as null. I will load it in beforeMount.
here is the pseudo-code:
<th v-for="item in computed_list">
{{ item.name }}
</th>
<script>
export default {
name: 'test',
data () {
return {
whole_list: null
}
},
beforeMount () {
this.load()
},
computed: {
computed_list: function() {
if (!this.series) return []
return this.whole_list.slice(1,3)
}
},
methods: {
async load () {
let res = await some_api_call()
this.whole_list = res['data']
}
}
}
</script>
But somehow it failed to render the list, and report TypeError: Cannot read property 'name' of null.
I'm new to Vue and not very familiar with its lifecycle. The basic idea is to render list of data, but those data are loaded somehow after the Vue instance is created. Not sure if it's the correct way to do this.
Initializing a data item to null breaks the VueJS state watching functionality so it won't know about changes to it. Initialize it as an empty object or array instead.
https://012.vuejs.org/guide/best-practices.html
The reason for this is that Vue observes data changes by recursively walking the data object and converting existing properties into reactive getters and setters using Object.defineProperty. If a property is not present when the instance is created, Vue will not be able to track it.
You don’t have to set every single nested property in your data though. It is ok to initialize a field as an empty object, and set it to a new object with nested structures later, because Vue will be able to walk the nested properties of this new object and observe them.

How can I make an Ember computed property depend on all descendent properties of a variable?

I'm trying to create a computed property that I want to be reevaluated whenever any value in a deeply nested object changes. I understand that myObj.[] can be used to reevaluate computed properties whenever any object in an array changes, but I want this to be recursive.
eg I have
// should recalculate whenever myObj.x.y.z changes, or when myObj.a.b.c changes
computed('myObj', function() {
// ...
})
I don't know in advance exactly how the object is structured, and it may be arbitrarily deep.
Neither computed('myObj.[]', ...) nor computed('myObj.#each', ...) seem to work for this.
Any ideas how to do this?
In Ember it is possible to define computed properties at runtime
import { defineProperty, computed } from '#ember/object';
// define a computed property
defineProperty(myObj, 'nameOfComputed', computed('firstName', 'lastName', function() {
return this.firstName+' '+this.lastName;
}));
So taking that a step further, you could dynamically create whatever computed property key string you want at runtime (this could be in component's init() or something):
// define a computed property
let object = {
foo: 'foo',
bar: 'bar'
}
this.set('myObj', object);
let keys = Object.keys(object).map((key) => {
return `myObj.${key}`
});
defineProperty(this, 'someComputed', computed.apply(this, [...keys, function() {
// do something here
}]));
It's up to you to figure out how to properly recursively traverse your objects for all the dependent keys without creating cycles or accessing prototype keys you don't want...or to consider whether or not this is even that good of an idea. Alternatively, you could try to handle the setting of these properties in such a way that retriggers a computation (which would be more in line with DDAU). I can only speculate from what you've provided what works but it's certainly possible to do what you want. See this twiddle in action
could you try anyone computed/obeserver like below..
But try to prefer the computed.
import { observer } from '#ember/object';
import EmberObject, { computed } from '#ember/object';
partOfNameChanged1: observer('myObj','myObj.[]','myObj.#each', function() {
return 'myObj is changed by obeserver';
})
partOfNameChanged2: computed ('myObj','myObj.[]','myObj.#each', function() {
return 'myObj is changed by computed';
})
then in your handlebar/template file
{{log 'partOfNameChanged1 is occured' partOfNameChanged1}}
{{log 'partOfNameChanged2 is occured' partOfNameChanged2}}
Then you have to associate/assign this partOfNameChanged1 / partOfNameChanged2 to some where in the handlebar or to any other variable in your .js file.
As long as you have not assigned this computed/observer property partOfNameChanged1 /partOfNameChanged2 to somewhere, then you will not get it's value.

How to use custom object methods with Vuex?

I have several custom js objects, where I encapsulated needle logic.
So, these objects don't have relation with vuex at all, something like that:
export default class Property {
constructor(object) {
// some logic
}
addChild(property) {
// some logic
}
}
Also, I have button in my vue component, which firing vue method:
methods: {
addItem() {
this.property.addChild();
},
},
And there is problem:
this.property - it is object from vuex store.
So, when I call method in such way, I get vue error:
Error: [vuex] Do not mutate vuex store state outside mutation handlers.
Yeah, I understand, what Vue wants.
But for me it is more clear to encapsulate some complex logic in needle objects. Also, I want to use vuex for global app state.
So, please, could you share experience how to deal with vuex and custom object methods?
If you want to use vuex you simply have to use mutation to alter it's states.
So, in the the Property object's addChild function,
where you would alter state, I assume you would do it like
Store.state.xxx = 'new'
Instead of doing that, you call mutation like
Store.commit('alterState')
There's not too much difference in terms of complexity, right?

Categories

Resources