Extending and debugging

Debugging common problems

This page is a list of symptoms. Each one comes with what it usually means and what to do about it — most are not bugs, but a design decision meeting somebody who did not know about it yet.

Nothing happens, the HTML shows up raw

Check, in this order: the file loaded (the network tab answers that in a second); it does not carry data-manual without a call to V.start(); and the console has no expression syntax error, which shows up with the exact position.

If the page uses components or directives of your own registered in another file, that registration has to happen before V.start().

The content flashes before rendering

<style>[v-cloak] { display: none !important; }</style>
<div v-cloak v-data="{}">...</div>

My CSS stopped working

Almost always a selector leaning on a v-* attribute. Once the library processes the element, the attribute leaves the document, and [v-tab] { ... } stops matching anything. For the same reason, el.getAttribute('v-something') returns null and querySelectorAll('[v-show]') comes back empty.

Use classes or data-*. If you really do need the old behaviour, V.config.cleanAttributes = false — or data-keep-attributes on the script tag — keeps everything in the HTML.

The value changes but the screen does not

Three causes, in order of how often they come up:

Maximum call stack, or a loop warning in the console

Some effect is writing to the same key it reads. The scheduler stops the repetition and warns. Look the expression over: it is usually a v-effect assigning to a variable it reads itself.

v-for loses the focus of a field when the list changes

The :key is missing. With no key, the library only knows the position, and reordering recreates the elements. With :key="item.id", they are reused and moved. The key has to be stable: the index will not do, because it changes along with the order.

v-if and v-for on the same element do not work

Both take control of the node. Put the condition on a child, or filter in the v-for expression itself. The lists page shows both ways.

window, document and fetch are undefined in expressions

That is on purpose: only a closed list of globals is exposed, and it is what makes running under a restrictive Content Security Policy possible. To reach the DOM and services, use the magic variables — $el, $refs, $http, $storage, $clipboard. To expose something of your own:

V.config.globals.myFunction = myFunction;

The V object is not available inside expressions either, for the same reason.

How do I write a multi-line function in an attribute?

Do not. The parser takes expressions, not blocks. Put the logic in a method of the v-data, of a store, or of the root scope:

V.data({ clear() { this.items = []; this.total = 0; } });
<button @click="clear()">Clear</button>

The component does not see the v-data around it

That is the default behaviour: components isolate the scope, so as not to depend by accident on the place they were pasted into. Pass the value in as a prop, or declare inheritScope: true in the definition.

The opposite confuses people too: the content of a <slot> belongs to the scope of whoever wrote the tag, not to the component's. Scoped slots do not exist.

A stretch of the page disappears with no error at all

If the stretch that disappeared comes right after a component tag, look at how that tag was closed. HTML does not accept self-closing outside the known tags: <VInput ... /> closes nothing, and the browser puts the whole rest of the block inside the component. Always write <VInput ...></VInput>.

The interpolation showed up raw on screen

Two causes. The first: the stretch is inside <pre>, <code>, <script>, <style>, <textarea> or a v-ignore, where the sweep deliberately does not go.

The second: the text between the braces is not an expression the library can read. When parsing fails, the stretch stays as it is, on purpose — it is what stops a lone { in a paragraph from becoming an error on screen. An object inside the expression ({ $t('items', { n: total }) }) and a multi-line expression both work; what does not work is what would not work in an attribute either, such as function and new.

Known details, with a workaround

These are waiting on a fix

The tools

When the symptom is not on this list, the reactivity inspector page shows how to watch the scopes, the effects and the requests happening — and how to install a global error handler for what slips through in production.

<div v-data="{ n: 0 }">
  <button @click="n++; $log('n is now', n, 'scope:', $data)">
    Add and log to the console
  </button>
  <p>{ n }</p>
</div>