Popular Pages

Our Work

See some of our best, most challenging projects.

Craft CMS

We're Craft CMS experts (and an Official Partner).

Using Vue.js with Server Rendered Form Input Values

Masuga Design
Catherine K. Sep 10, 2021 Read time: 4 minute read
How to Use Vue.js on Pre-Rendered Forms

Vue.js is great for interactive forms, and updating page contents based on user interaction with a form. But Vue.js isn't so great for forms with input values already rendered from the server. We'll look at how to get around that roadblock.

Rendered via what now?

Vue.js really shines in single-page webapps and webpages that are rendered mostly on the client-side. When there's little interaction with the server, or if server interactions can happen asynchronously, you shouldn't run into too many problems with using Vue.js for your forms. However, sometimes you'll need to load a dynamic form already populated with data from the server.

An example of the former is an empty contact form: none of the inputs have values (which come from the server) in them when the page first loads. An example of the latter is an account edit form: it has to get the user's data from the server and populate the form's fields with that data from the start so that the user can edit it. That's where the roadblock lies.

So what's the problem?

To quote the docs:

v-model will ignore the initial value, checked or selected attributes found on any form elements. It will always treat the current active instance data as the source of truth. You should declare the initial value on the JavaScript side, inside the data option of your component.

That means that any data that's already in the form input components on page load (server-side rendered) gets completely ignored by Vue. That firstName field's value, fetched by your CMS? (Our CMS of choice is currently Craft CMS, for reference) Non-existent in the eyes of Vue. The user's communications preferences checkboxes, also gone. It's very hard to have an "edit account" form when you can't access the user's account information in order to edit it.

Then how do we fix it?

There are a few options, and none of them are great.

  1. Don't render those inputs with data from the server upon load. Instead, fetch those input fields' values asynchronously (AJAX, axios, etc) in your form component's mounted and feed those values to your component's data object.
    • This isn't a great option if your form has lots of fields. You'll have to sort through the response json for each field's value and assign it to the correct data property, and the possibility for error in that process increases with each field.
  2. Render the input fields' initial values as data attributes on the elements themselves, fetch them during the component's mounted event, and update the component's props with their values.
    • This is certainly fewer steps and less code than Option 1, but it's still more work than one might expect to be necessary from a full-featured framework and for such a common and simple task.
  3. Get the data first and construct the form second. Get the data asynchronously and create the form, with its inputs populated, based on that data.
    • This approach doesn't really differ much from Option 1, except that you may end writing string templates, which is even less fun.

We prefer to go with Option 2, since it's the most straightforward approach.

Can I have an example?

Sure! Here's a simplified form, with data attributes that hold the input fields' values that are fetched from the server. A couple of notes here:

  1. Yes, this is a DOM template. That's not always the preferred practice for Vue components (for more information, see this article or the docs). However, in this case, our whole application is not a Vue application; just this one piece is. It would be impractical to rewrite significant portions of a page to accommodate a single component's preferred practices.
  2. Craft CMS uses Twig as its templating engine, and both Twig and Vue make use of double curly braces ( {{ }} ) as their delimiters. For that reason, we pass Vue a delimiters parameter to tell Vue to ignore its standard double curly braces and instead use a different delimiter.

The HTML

<div id="accountForm">
  <form method="post" accept-charset="UTF-8">
    <label>Field One</label>
    <input type="text" name="fields[fieldOne]" id="fieldOne" data-value="{{ currentUser.fieldOne }}" v-model="fieldOne">
    <label>Field Two</label>
    <input type="text" name="fields[fieldTwo]" id="fieldTwo" data-value="{{ currentUser.fieldTwo }}" v-model="fieldTwo">
    <label>Field Three</label>
    <input type="text" name="fields[fieldThree]" id="fieldThree" data-value="{{ currentUser.fieldThree }}" v-model="fieldThree">
  </form>
</div>

The Javascript

import { createApp } from 'vue/dist/vue.esm-bundler.js';

var accountFormApp = createApp({
  delimiters: ['${', '}'],
  data() {
    return {
      fieldOne: '',
      fieldTwo: '',
      fieldThree: ''
    }
  },
  mounted() {
    this.fieldOne = document.getElementById('fieldOne').getAttribute('data-value');
    this.fieldTwo = document.getElementById('fieldTwo').getAttribute('data-value');
    this.fieldThree = document.getElementById('fieldThree').getAttribute('data-value');
  }
});

accountFormApp.mount('#accountForm');

In Closing

Tl;dr: you can't get a form input's default value to be used by v-model if that value was fetched from the server on page load. You can put that value in a data attribute and add it to your component's data object, instead. It's a surprising limitation, but once you're aware of it and know your options, it's not difficult to work around.

Subscribe to our newsletter!

A few times a year we send out a newsletter with tips and info related to Craft CMS, technical SEO, and things we find interesting. No spam. Unsubscribe any time.

You Might Also Like

PageSpeed Insights Core Web Vitals

Improving Google Page Experience With Core Web Vitals

Ryan Masuga Aug 31, 2021  ·  12 minute read

Overall website performance has always been important but after Google's Page Experience updates in 2021, it's more important than ever. Improving your site's Core Web Vitals can drastically improve the page experience for your site visitors.