Vue: safe navigation operator ( ?. ) and null property paths

Created on 3 Jan 2017  ·  16Comments  ·  Source: vuejs/vue


Feature Request

Problem

While accessing the data from view in template expression, if a null object is used like below :

{{  book  }} 

View is rendered and displayed value is blank.

Suppose the template expression involves a property path, as in this next example where we’re displaying the name of a null book.

{{  book.name  }} 

This would throw a null reference error :
TypeError: Cannot read property 'name' of null.

Workaround

We can find a workaround for this using a conditional block like this:

<div v-if="book">
{{  book.name  }} 
</div>

But if we have a use case where we need a property path deep into the object some thing like this ?

a.b.c.d

Solution

We can use a safe navigation operator ( ?. ) or elvis operator similar to Angular 2. That can help in reducing a lot of conditional tags in a complex code.

Most helpful comment

It's 2020 and optional chaining is already implemented in ecmascript. When can we expect it to work in Vue templates?

https://github.com/tc39/proposal-optional-chaining

All 16 comments

Thanks for the suggestion, but I'm not a fan of the idea of introducing non-standard syntax into template expressions - which imo should be "just JavaScript" as much as possible. Also if you have a deep path that may or may not exist on each level of access, it sounds like code smell to me. Your model/state should be as predictable as possible.

In Vue, how does one handle the situation where book is loaded async, and initially has no value?

@saivarunk It gives me an error _./~/vue-loader/lib/template-compiler.js?id=data-v-8e3d2b58!./~/vue-loader/lib/selector.js?type=template&index
(Emitted value instead of an instance of Error) template syntax error invalid expression: v-bind:value="model.topics?.id_

Optional chaining (elvis operator) is stage-1 now:

https://github.com/tc39/proposal-optional-chaining

Could this be reconsidered? I'd love to see it added, as it can beautifully simplify code.

@lehni If optional chaining becomes available in Babel, then all you would need to do is enable the Babel plugin, there's no need for Vue to _support_ this syntax since it's just JavaScript.

Update: I found this @babel/plugin-proposal-optional-chaining so it could already work

@sirlancelot I am already using this plugin, and it works in JS code, but it does not work within the template expressions, e.g.

{{ book?.name }}

My bad, it looks like template compilation uses a customized version of _Buble_, not Babel... https://vue-loader.vuejs.org/en/features/es2015.html#es2015-in-templates

Oh I see, that explains a few things. I guess that means there's no flexibility here, except for if Vue would allow both engines to be plugged in for transpilation, using babel if it's there, falling back to buble if not. No idea if that's even possilbe.

in case anyone else comes here wanting to do this, I ended up using lodash lodash's get function which lets you do things like

_.get(a, 'b.c.d', 'optionalFallbackValueGoesHere')

to make this "get" function available to Vue I do

import lodashGet from 'lodash/get'
Vue.prototype.$get = lodashGet

in my entry.js

now in my Vue template I can use

{{ $get(a, 'b.c.d') }}

or if you want all of lodash available in your Vue templates you can use vue-lodash

I understand Evan You does not want Vue templating to morph into its own mutant language, but I don't agree having nullable properties with subproperties is a code smell, especially with the way I design my Vuex state with lookups by Id where additional information about a record may or may not exist

luckily Vue seems flexible enough that you can do anything JS from within a template, so it's all good once you get the hang of it :)

https://github.com/tc39/proposal-optional-chaining
Stage 3 now (and half-way to Stage 4).

@yyx990803, Maybe it is a time to implement it now?

It would need to be added to https://github.com/yyx990803/buble which was forked from https://github.com/bublejs/buble

It would need to be added to https://github.com/yyx990803/buble which was forked from https://github.com/bublejs/buble

Actually it should be added to Vue itself, because it throws Errors before any transpiling happens.

Just as a reminder, it's a little ugly, but javascript does have a safe traversal in a way.

from
dog.name
to
(dog || {}).name || null

from
person.job.salary.american()
to
((((person || {}).job || {}).salary || {}).american || () => null)()

But yes, person?.job?.salary?.american() would be much nicer

It's 2020 and optional chaining is already implemented in ecmascript. When can we expect it to work in Vue templates?

https://github.com/tc39/proposal-optional-chaining

I guess someone should take courage and open this as a new issue.

Was this page helpful?
0 / 5 - 0 ratings