Vuex store strange behavior in component - vue.js

The store data can be accessed in a component embeded in the HTML directly as:
{{$store.state.notificationArea.cart.total;}}
This works fine, However, it doesn't work in the computed attribute of the same controller as:
computed: {
total: function () {
return this.$store.state.notificationArea.cart.total;
}
}
Have been trying to resolve it for three days, please help.

A computed property is a function that returns a value it should be declared like total:function(){}, total:()=>{} or total(){} :
computed: {
total:()=>{
return this.$store.state.notificationArea.cart.total;
}
}
And that property which you're referencing should be initialized like :
const state={
notificationArea:{
cart:{
total:0,
}
}
}
....

Related

$nuxt is not defined when using $nuxt.route in computed

I'm looking to use the following for my nuxt routes within the computed property. All seemed to be working until 3mins ago when I started getting $nuxt is not defined. Removing the following code makes the app run again. What am I doing wrong here?
computed: {
updateActiveRoute() {
return $nuxt.$route.params.name ? $nuxt.$route.params.name : 'Hello'
}
},
watch: {
updateActiveRoute(newVal) {
this.activeRoute = newVal
}
}
Thanks
$nuxt, precisely window.$nuxt is only available on client-side and should only be used as escape hatch.
You can access the route object via this.$route instead when using the Options API.
computed: {
updateActiveRoute() {
return this.$route.params.name ? this.$route.params.name : 'Hello'
}
},
watch: {
updateActiveRoute(newVal) {
this.activeRoute = newVal
}
}
Use this.$nuxt
Only within the template you can access variables without this.

Is there a way to pass the returning value of a method as a prop to a Vue component?

I have a Vue.js component (named <dynamic-input/>) which accepts a prop (called input). I'm trying to pass the returning value of a method (named normalizeInput) which is defined in the parent component:
template
<div v-for="input in inputList" :key="input.id">
<dynamic-input :input="normalizeInput(input)" />
</div>
script
methods: {
normalizeInput(input) {
//do something with input
return normalizedInput;
}
}
Apparently this doesn't work; Is there a way to achieve this? Am I Doing Something Wrong?
I'm Using nuxt v2.15.7
You've to use a computed property that returns a function with the input as parameters :
computed: {
normalizeInput() {
return (input) =>{
return normalizedInput;
}
}
}

How do I check whether or not a typed property has a value in Vue

I'm using Vue in vanilla JS and have a property defined in my data of type string which looks like this
data() {
return {
DimensionSetting: { type : String }
}
}
I have an element in my template that I want to toggle off when a value is passed into DimensionSetting however I can't figure out how I need to check for it in the v-if logic. I tried v-if="!this.DimensionSetting" and v-if="this.DimensionSetting === undefined" and v-if="this.DimensionSetting === null". None of these make the element visible when the value is empty. What do I need to do to properly check that kind of property?
It looks like you're incorrectly mixing a data property declaration with a props declaration.
If DimensionSetting is supposed to be a public property that receives values from a parent component, it should be declared under props:
export default {
props: {
DimensionSetting: {
type: String,
}
}
}
On the other hand, if DimensionSetting is supposed to be a local property, private to the component itself, then it should be returned from data(). There is no type field like there is for props declarations:
export default {
data() {
return {
DimensionSetting: ''
}
}
}
In either case, using the ! operator on the prop should be enough to check for an empty string:
<p v-if="!DimensionSetting">Empty</p>
demo
try adding,
data(){
return{
DimensionSetting: { type : String ,default:false}
}
}
and then v-if="!DimensionSetting"

How to passing computed with param to props of child component?

I'm a newbie in Vuejs. I'm trying passing computed with param to props of child component but it's error.
This is my code:
<FloatingInput
:type="'text'"
:name="'username'"
:error="fieldError('username')"
>
<FloatingInput
:type="'password'"
:name="'password'"
:error="fieldError('password')"
>
And in the script:
computed: {
fieldError: {
get: function () {
return this.error[field]; // will return false or message error
},
set: function (field) {
this.error[field];
}
},
}
Computed properties are meant to be pure. This means that computed properties rely solely on the state of the component, and should not have side-effects. This allows Vue to only recalculate computed properties whenever the data they rely on changes. For this reason you can not call a computed property. You must use a method.
Luckily for you, what you want to do is just a key lookup in an object, so you can just use a data attribute and lookup the field.
<FloatingInput
type="text"
name="username"
:error="fieldErrors['username']"
>
data () {
fieldErrors: {}
},
methods: {
setFieldError(field, error) {
this.$set(this.fieldErrors, field, error);
}
}

Using $refs in a computed property

How do I access $refs inside computed? It's always undefined the first time the computed property is run.
Going to answer my own question here, I couldn't find a satisfactory answer anywhere else. Sometimes you just need access to a dom element to make some calculations. Hopefully this is helpful to others.
I had to trick Vue to update the computed property once the component was mounted.
Vue.component('my-component', {
data(){
return {
isMounted: false
}
},
computed:{
property(){
if(!this.isMounted)
return;
// this.$refs is available
}
},
mounted(){
this.isMounted = true;
}
})
I think it is important to quote the Vue js guide:
$refs are only populated after the component has been rendered, and they are not reactive. It is only meant as an escape hatch for direct child manipulation - you should avoid accessing $refs from within templates or computed properties.
It is therefore not something you're supposed to do, although you can always hack your way around it.
If you need the $refs after an v-if you could use the updated() hook.
<div v-if="myProp"></div>
updated() {
if (!this.myProp) return;
/// this.$refs is available
},
I just came with this same problem and realized that this is the type of situation that computed properties will not work.
According to the current documentation (https://v2.vuejs.org/v2/guide/computed.html):
"[...]Instead of a computed property, we can define the same function as a method. For the end result, the two approaches are indeed exactly the same. However, the difference is that computed properties are cached based on their reactive dependencies. A computed property will only re-evaluate when some of its reactive dependencies have changed"
So, what (probably) happen in these situations is that finishing the mounted lifecycle of the component and setting the refs doesn't count as a reactive change on the dependencies of the computed property.
For example, in my case I have a button that need to be disabled when there is no selected row in my ref table.
So, this code will not work:
<button :disabled="!anySelected">Test</button>
computed: {
anySelected () {
if (!this.$refs.table) return false
return this.$refs.table.selected.length > 0
}
}
What you can do is replace the computed property to a method, and that should work properly:
<button :disabled="!anySelected()">Test</button>
methods: {
anySelected () {
if (!this.$refs.table) return false
return this.$refs.table.selected.length > 0
}
}
For others users like me that need just pass some data to prop, I used data instead of computed
Vue.component('my-component', {
data(){
return {
myProp: null
}
},
mounted(){
this.myProp= 'hello'
//$refs is available
// this.myProp is reactive, bind will work to property
}
})
Use property binding if you want. :disabled prop is reactive in this case
<button :disabled="$refs.email ? $refs.email.$v.$invalid : true">Login</button>
But to check two fields i found no other way as dummy method:
<button :disabled="$refs.password ? checkIsValid($refs.email.$v.$invalid, $refs.password.$v.$invalid) : true">
{{data.submitButton.value}}
</button>
methods: {
checkIsValid(email, password) {
return email || password;
}
}
I was in a similar situation and I fixed it with:
data: () => {
return {
foo: null,
}, // data
And then you watch the variable:
watch: {
foo: function() {
if(this.$refs)
this.myVideo = this.$refs.webcam.$el;
return null;
},
} // watch
Notice the if that evaluates the existence of this.$refs and when it changes you get your data.
What I did is to store the references into a data property. Then, I populate this data attribute in mounted event.
data() {
return {
childComps: [] // reference to child comps
}
},
methods: {
// method to populate the data array
getChildComponent() {
var listComps = [];
if (this.$refs && this.$refs.childComps) {
this.$refs.childComps.forEach(comp => {
listComps.push(comp);
});
}
return this.childComps = listComps;
}
},
mounted() {
// Populates only when it is mounted
this.getChildComponent();
},
computed: {
propBasedOnComps() {
var total = 0;
// reference not to $refs but to data childComps array
this.childComps.forEach(comp => {
total += comp.compPropOrMethod;
});
return total;
}
}
Another approach is to avoid $refs completely and just subscribe to events from the child component.
It requires an explicit setter in the child component, but it is reactive and not dependent on mount timing.
Parent component:
<script>
{
data() {
return {
childFoo: null,
}
}
}
</script>
<template>
<div>
<Child #foo="childFoo = $event" />
<!-- reacts to the child foo property -->
{{ childFoo }}
</div>
</template>
Child component:
{
data() {
const data = {
foo: null,
}
this.$emit('foo', data)
return data
},
emits: ['foo'],
methods: {
setFoo(foo) {
this.foo = foo
this.$emit('foo', foo)
}
}
}
<!-- template that calls setFoo e.g. on click -->