-
-
Save jesseleite/3507f7ad3dd062b9e5f7592c899bf297 to your computer and use it in GitHub Desktop.
Custom Vue JS Form Driver for Statamic
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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' }); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<!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> |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<?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, | |
]; | |
} | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<?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 | |
} | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<!-- 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 }} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
You're a genius my friend. Many thanks for this example.