Skip to content

Instantly share code, notes, and snippets.

@jesseleite
Last active June 7, 2023 09:32
Show Gist options
  • Star 3 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save jesseleite/3507f7ad3dd062b9e5f7592c899bf297 to your computer and use it in GitHub Desktop.
Save jesseleite/3507f7ad3dd062b9e5f7592c899bf297 to your computer and use it in GitHub Desktop.
Custom Vue JS Form Driver for Statamic
import Vue from 'vue'
// Ensure Vue has access to global `Statamic` component
Vue.prototype.Statamic = window.Statamic;
// Create `<form-conditions>` component to be used with Vue JS driver
Vue.component('form-conditions', {
props: ['initialData'],
data() {
return {
formData: this.initialData,
};
},
render() {
return this.$scopedSlots.default({ formData: this.formData });
},
});
// Ensure your app has a parent vue instance for child components to run in
new Vue({ el: '#app' });
<!doctype html>
<html>
<head>
<title>{{ title }}</title>
</head>
<body>
<!-- Ensure your app has a parent vue instance for child components to run in -->
<div id="app">
{{ partial:nav }}
{{ template_content }}
{{ partial:footer }}
</div>
<!-- Include Statamic's front-end `helpers.js` file -->
<script src="/vendor/statamic/frontend/js/helpers.js"></script>
<!-- As well as your built `site.js` file with the `form-conditions` component -->
<script src="{{ mix src='/js/site.js' }}"></script>
</body>
</html>
<?php
namespace App\Forms;
use Statamic\Forms\JsDrivers\AbstractJsDriver;
class Vue extends AbstractJsDriver
{
/**
* Render `<form-conditions>` vue component around your `<form>`
*/
public function render($html)
{
$data = Statamic::modify($this->getInitialFormData())->toJson()->entities();
return '<form-conditions :initial-data="'.$data.'" v-slot="{ formData }">'.$html.'</form-conditions>';
}
/**
* Add `show_field` javascript to renderable field data, with reference to `formData` object in the vue data
*/
public function addToRenderableFieldData($field, $data)
{
$conditions = Statamic::modify($field->conditions())->toJson()->entities();
return [
'show_field' => 'Statamic.$conditions.showField('.$conditions.', formData)',
];
}
/**
* Add `v-model` to bind each field's input to `formData` object in the vue data
*/
public function addToRenderableFieldAttributes($field)
{
$dataKey = 'formData.'.$field->handle();
// Because Vue warns against `v-model` on file inputs, use `@change` to bind data on those inputs
if ($field->type() === 'assets') {
return [
'@change' => $dataKey.' = $event.target.files[0].name',
];
}
return [
'v-model' => $dataKey,
];
}
}
<?php
namespace App\Providers;
use App\Forms\Vue;
use Illuminate\Support\ServiceProvider;
class AppServiceProvider extends ServiceProvider
{
public function register()
{
Vue::register(); // Register your custom `Vue` JS driver with Statamic
}
}
<!-- Tell Statamic to use the registered `vue` JS driver -->
{{ form:contact js="vue" }}
<!-- Dynamically loop over fields, showing/hiding using a `v-if` -->
{{ fields }}
<template v-if="{{ show_field }}">
<div class="p-2">
<label>{{ display }}</label>
<div class="p-1">{{ field }}</div>
</div>
</template>
{{ /fields }}
<!-- Hard code a field, showing/hiding using a `v-if`, with a `v-model` on the form input to sync with Vue -->
<template v-if="{{ show_field:inquiry }}">
<label>
Inquiry
<input type="text" name="inquiry" value="{{ old:inquiry }}" v-model="formData.inquiry" />
</label>
</template>
<button type="submit">Submit</button>
{{ /form:contact }}
@grantholle
Copy link

You're a genius my friend. Many thanks for this example.

@jesseleite
Copy link
Author

@grantholle 🤘 ❤️

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment