Reputation: 1766
I have created vue and electron app using @vue/cli-service 4.2 in that I am facing a issue of optional chaining.
I can't use ? for validating the condition like (@babel/plugin-proposal-optional-chaining)
eg. a?.b?.c its means it check weather a exist then check for b otherwise return false same as template expression in angular.
Any one have idea how to configure optional chaining in vuejs.
Upvotes: 31
Views: 36915
Reputation: 51
You can use loadash's get method in this case:
_.get(object, path, [defaultValue])
Gets the value at path of object. If the resolved value is undefined, the defaultValue is returned in its place.
https://lodash.com/docs/4.17.15#get
var object = { 'a': [{ 'b': { 'c': 3 } }] };
_.get(object, 'a[0].b.c');
// => 3
_.get(object, 'a.b.c', 'default');
// => 'default'
Upvotes: 0
Reputation: 16131
July 2022 Update: It works with Vue 2.7 (https://blog.vuejs.org/posts/vue-2-7-naruto.html)
2.7 also supports using ESNext syntax in template expressions.
Upvotes: 0
Reputation: 1
Use getSafe() method way for template and js files :)
<template><div>
{{getSafe(() => obj.foo.bar)}} <!-- returns 'baz' -->
{{getSafe(() => obj.foo.doesNotExist)}} <!-- returns undefined -->
</div></template>
<script>
export default {
data() {
return {obj: {foo: {bar: 'baz'}}};
},
methods: {getSafe},
};
function getSafe(fn) {
try { return fn(); }
catch (e) {}
}
</script>
Upvotes: 0
Reputation: 604
This doesn't work exactly the same but I think, in this context, it may be event better for most cases.
I used Proxy
for the magic method effect. You just need to call the nullsafe
method of an object and from there on, just use normal chaining.
In some versions of VueJs you can't specify a default value. It perceives our null safe value as an object (for good reason) and JSON.stringify
it, bypassing the toString
method. I could override toJSON
method but you can't return the string output. It still encodes your return value to JSON. So you end up with your string in quotes.
const isProxy = Symbol("isProxy");
Object.defineProperty(Object.prototype, 'nullsafe', {
enumarable: false,
writable: false,
value: function(defaultValue, maxDepth = 100) {
let treat = function(unsafe, depth = 0) {
if (depth > maxDepth || (unsafe && unsafe.isProxy)) {
return unsafe;
}
let isNullish = unsafe === null || unsafe === undefined;
let isObject = typeof unsafe === "object";
let handler = {
get: function(target, prop) {
if (prop === "valueOf") {
return target[prop];
} else if (typeof prop === "symbol") {
return prop === isProxy ? true : target[prop];
} else {
return treat(target[prop], depth + 1);
}
}
};
let stringify = function() {
return defaultValue || '';
};
let dummy = {
toString: stringify,
includes: function() {
return false;
},
indexOf: function() {
return -1;
},
valueOf: function() {
return unsafe;
}
};
return (isNullish || isObject) ? (new Proxy(unsafe || dummy, handler)) : unsafe;
};
return treat(this);
}
});
new Vue({
el: '#app',
data: {
yoMama: {
a: 1
}.nullsafe('xx'),
yoyoMa: {
b: 1
}
}
});
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.5.17/vue.js"></script>
<div id="app">
{{ yoMama.yoyoMa.yoMama.yoyoMa.yoMama }}
<hr> {{ yoyoMa.nullsafe('yy').yoMama.yoyoMa.yoMama.yoyoMa }}
</div>
Upvotes: 1
Reputation: 640
Try vue-template-babel-compiler
It uses Babel
to enable Optional Chaining(?.)
, Nullish Coalescing(??)
and many new ES syntax for Vue.js SFC
.
npm install vue-template-babel-compiler --save-dev
// vue.config.js
module.exports = {
chainWebpack: config => {
config.module
.rule('vue')
.use('vue-loader')
.tap(options => {
options.compiler = require('vue-template-babel-compiler')
return options
})
}
}
// nuxt.config.js
export default {
// Build Configuration: https://go.nuxtjs.dev/config-build
build: {
loaders: {
vue: {
compiler: require('vue-template-babel-compiler')
}
},
},
// ...
}
Please refer to REAMDE for detail usage
Support for Vue-CLI, Nuxt.js, Webpack
, any environment use vue-loader v15+
.
Upvotes: 11
Reputation: 1858
/*
* Where to use: Use in vue templates to determine deeply nested undefined/null values
* How to use: Instead of writing parent?.child?.child2 you can write
* isAvailable(parent, 'child.child2')
* @author Smit Patel
* @params {Object} parent
* {String} child
* @return {Boolean} True if all the nested properties exist
*/
export default function isAvailable(parent, child) {
try {
const childArray = String(child).split('.');
let evaluted = parent;
childArray.forEach((x) => {
evaluted = evaluted[x];
});
return !!evaluted;
} catch {
return false;
}
}
<template>
<div>
<span :v-if="isAvailable(data, 'user.group.name')">
{{ data.user.group.name }}
<span/>
</div>
</template>
<script>
import isAvailable from 'file/path';
export default {
methods: { isAvailable }
}
</script>
Upvotes: 1
Reputation: 41
After search many possibilities, I maked one function to help me.
Make one js file to save the helper function and export it
const propCheck = function (obj = {}, properties = ""){
const levels = properties.split(".");
let objProperty = Object.assign({}, obj);
for ( let level of levels){
objProperty = objProperty[level];
if(!objProperty)
return false;
}
return true;
}
export default propCheck;
And install this function for globally in the Vue instance
Vue.prototype.$propCheck = propCheck;
After use in your template
<span>{{$propCheck(person, "name")}}</span>
or
<span>{{$propCheck(person, "contatcs.0.address")}}</span>
or
<span>{{$propCheck(person, "addres.street")}}</span>
Upvotes: 0
Reputation: 1701
One quick update is that Vue 3 comes bundled with support for optional chaining.
To test you can try compiling the below Vue component code.
<template>
<div id="app" v-if="user?.username">
@{{ user?.username }} - {{ fullName }} <strong>Followers: </strong>
{{ followers }}
<button style="align-self: center" @click="followUser">Follow</button>
</div>
</template>
<script lang="ts">
import { defineComponent } from 'vue'
export default defineComponent({
name: 'App',
props: {
test: Object
},
data() {
return {
followers: 0,
user: {
id: 1,
test: {},
username: '_sethAkash',
firstName: undefined,
lastName: 'Seth',
email: '[email protected]',
isAdmin: true
}
}
},
computed: {
fullName(): string {
//
return `${this?.test?.firstName} ${this?.user?.lastName}`
}
},
methods: {
followUser: function () {
this.followers += 1
}
},
watch: {
followers(newFollowerCount, oldFollowerCount) {
if (oldFollowerCount < newFollowerCount) {
console.log(`${this?.user?.username} has gained a follower!`)
}
}
},
mounted() {
this.followUser()
}
})
</script>
Upvotes: 14
Reputation: 349
According to this comment on an issue here
You could create a global mixin and use the eval
function to evaluate the expression.
Example:
Vue.mixin({
methods: {
$evaluate: param => eval('this.'+param)
}
});
In the template:
<template>
<p>{{ $evaluate('user?.name') }}</p>
</template>
They also added that it might not be perfect:
Although it's still no substitute for the real operator, especially if you have many occurrences of it
As stated above, using eval
may bring some unintended problems, I suggest you use a computed property instead.
In the SFC:
<template>
<p>{{ userName }}</p>
</template>
<script>
export default {
data(){
return {
user: {
firstName: 'Bran'
}
}
},
computed: {
userName(){
return this.user?.firstName
}
}
}
</script>
Upvotes: 8