Set Initial value to vue.js model which is directly available in HTML

Vue really isn't designed to init from the HTML, however, one approach is to use a directive to init the values. This is loosely based around the same idea as Angular's ng-init:

Vue.directive('init', {
  bind: function(el, binding, vnode) {
    vnode.context[binding.arg] = binding.value;
  }
});

That essentially takes the binding argument, which is the name after the colon (see below) and sets it to the given value on the Vue instance, which you can then use as:

<input v-model="subscribed" type="checkbox" v-init:subscribed="<?=($checked) ? 'true' : 'false'?>"  />

A few caveats with that though, firstly you still need to declare your data properties upfront, it won't dynamically inject them, secondly everything get evaluated as JavaScript, so if you want to init with a string it needs to be wrapped in single quotes and finally it won't understand camelCase, so if you want to set camelCase data properties you will need to write a kebab-case to camelCase conversion in the directive.

Here's your updated snippet in a JSFiddle: https://jsfiddle.net/evnctym1/


Here's some possible concepts you might find useful when binding your backend data with Vue.

0. Build a REST API and use it

Preferred approach but sometimes this is not possible. For example, if you don't have full control over the backend code.

1. You could assign global variables

To get your data inside Vue context with PHP/HTML:

<script>
var myDataFromPhp = {
  stringExample: '<?php echo "Hello World!"; ?>',
  objectExample: JSON.parse('<?php echo json_encode(["Hello again" => "Greetings from Mars!"]); ?>'),
}
</script>

In Vue:

data: {
  someString: window.myDataFromPhp && window.myDataFromPhp.stringExample? window.myDataFromPhp.stringExample : '',
  someObject: window.myDataFromPhp && window.myDataFromPhp.objectExample? window.myDataFromPhp.objectExample : {},
},

Maybe just stuff all data in one object at the PHP side to make it prettier. You could also use variable naming that says it's read only and meant to be static: var _OBJECT_EXAMPLE = ...


2. If you don't feel like exposing a global variable inside a <script> tag

When binding form data to Vue, the following has worked for me when initialising Vue app in specific state. This is useful if you just have one little thing you need to bind.

Inside your Vue app's scope:

<input name="someInputData" type="hidden" :value="someInputData = 'Heya!'">

Then declare data in Vue app:

data: {
  someInputData: undefined, // NOTE: This one is initialised in template element input[name="someInputData"]
},

I'm not sure if this has any async side effects. Use with caution and test.


3. Use vanilla JS:

In HTML:

data: {
  someInputData: document.getElementById('my-hidden-input')? document.getElementById('my-hidden-input').value : undefined, 
}

Just make sure there's only unique DOM elements or your data will be all wrong ...


This is not in the spirit of Vue, as you should have logic outside the template when feasible, but here's a clever workaround that should work in most situations

<input 
  v-model="foobar"
  :run="!foobar ? foobar = 1 : true"
/>

:run isn't a special attribute, it's completely arbitrary. I use it to define the value of what I'm v-modeling.

In my case, this was useful because I needed to v-model on an index of an array where the index doesn't exist yet. The template is creating the index it v-models on. I do advise against the above workaround and suggest testing throughly if you use it for potential side effects, but it will let you init a value inline in the template.

Tags:

Vue.Js

Vuejs2