vormjs
Version:
Write your forms in JSON and HTML, use the same API.
434 lines (364 loc) • 9.77 kB
HTML
<html>
<head>
<title>Dynamic forms</title>
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.3.14/angular.min.js"></script>
<!-- <script src="https://cdnjs.cloudflare.com/ajax/libs/angular.js/1.3.14/angular-animate.min.js"></script> -->
<script src="../../node_modules/angular-animate/angular-animate.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/lodash.js/3.5.0/lodash.min.js"></script>
<!-- vorm -->
<script src="../../vorm.js"></script>
<!-- end of vorm -->
<script src="https://code.jquery.com/jquery-2.1.3.min.js"></script>
<link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.4/css/bootstrap.min.css">
<script src="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.4/js/bootstrap.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/highlight.js/8.4/highlight.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/highlight.js/8.4/languages/javascript.min.js"></script>
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/highlight.js/8.4/styles/monokai_sublime.min.css">
<script id="app">
angular.module('app', [ 'vorm', 'ngAnimate' ])
.controller('FormController', [ '$scope', function ( $scope ) {
var ctrl = this,
fields;
fields = [
{
name: 'title',
type: 'text',
label: 'Post title',
required: true,
data: {
placeholder: 'What would the title of the post be?'
}
},
{
name: 'content',
type: 'textarea',
label: 'Content',
required: true,
data: {
placeholder: 'What do you have to say?'
}
},
{
name: 'category',
type: 'select',
label: 'Category',
data: {
options: getCategoryOptions()
},
required: true
},
{
name: 'sub_category',
type: 'select',
label: 'Sub category',
data: {
options: [ '$values', function ( $values ) {
var options = $values.category ? $values.category.children : [];
return options;
}]
},
when: [ '$values', function ( $values ) {
return (
$values.category &&
$values.category.children &&
$values.category.children.length > 0
);
}],
required: true
},
{
name: 'schedule',
type: 'checkbox',
data: {
checkboxLabel: 'Schedule this post for later'
},
defaults: true
},
{
name: 'schedule_date',
type: 'date',
disabled: '!schedule',
required: true,
defaults: new Date()
},
{
name: 'generateDeeplinkId',
type: 'checkbox',
data: {
checkboxLabel: 'Automatically generate a deeplink'
},
defaults: true
},
{
name: 'deeplinkId',
type: 'text',
required: true,
disabled: [ '$values', function ( $values ) {
return !!$values.generateDeeplinkId;
}]
}
];
function getCategoryOptions ( ) {
return [
{
label: 'Programming',
value: {
id: 1,
children: [
'JavaScript',
'Ruby',
'Go',
'PHP'
].map(function ( lang ) {
return {
value: lang,
label: lang
};
})
}
},
{
label: 'Culture',
value: {
id: 2,
children: [
'Music',
'Movies',
'Books'
].map(function ( type ) {
return {
value: type,
label: type
};
})
}
},
{
label: 'Other',
value: {
id: 3,
children: [
{
value: 'Other',
label: 'Other'
}
]
}
}
];
}
ctrl.getFields = function ( ) {
return fields;
};
ctrl.handleSubmit = function ( values ) {
console.log('submitted with', values);
};
function setDeeplinkId ( ) {
var form = $scope.vormForm;
if(form.getValue('title')) {
form.setValue('deeplinkId', form.getValue('title').replace(/[^A-Za-z0-9]/g, '-').toLowerCase());
}
}
ctrl.handleChange = function ( name ) {
console.log('change', arguments);
var form = $scope.vormForm;
switch(name) {
case 'title':
if(form.getValue('generateDeeplinkId')) {
setDeeplinkId();
}
break;
case 'generateDeeplinkId':
setDeeplinkId();
break;
case 'schedule':
form.setValue('schedule_date', new Date());
break;
}
};
}])
.config([ 'vormTemplateServiceProvider', function ( vormTemplateServiceProvider ) {
vormTemplateServiceProvider.modifyModelTemplates(function ( el, type ) {
if(type !== 'checkbox') {
el.addClass('form-control');
}
return el;
});
vormTemplateServiceProvider.modifyControlTemplate(function ( el ) {
el.find('vorm-display').addClass('flip');
el.find('vorm-edit').addClass('flip');
return el;
});
}]);
</script>
<style>
.vorm-field-label {
padding: 4px 0;
}
.vorm-field-label:empty {
display: none;
}
.vorm-field-required .vorm-field-label::after {
content: " (*)";
}
vorm-edit,
vorm-display {
display: flex;
}
.vorm-control-clear-button {
margin-left: 5px;
}
.vorm-delegate-button {
margin-top: 10px;
}
.vorm-field-empty vorm-display span::before {
content: "-";
}
[vorm-field=generateDeeplinkId],
[vorm-field=schedule] {
padding-top: 10px;
}
[vorm-field] {
transition:0.5s ease-in opacity;
}
[vorm-field].ng-enter {
opacity: 0;
}
[vorm-field].ng-enter-active {
opacity: 1;
}
[vorm-field].ng-leave {
opacity: 1;
}
[vorm-field].ng-leave-active {
opacity: 0;
}
vorm-control {
display: block;
position: relative;
margin-bottom: 10px;
}
vorm-display {
padding: 6px 12px;
border: 1px solid transparent;
}
vorm-edit,
vorm-display {
top: 0;
right: 0;
left: 0;
}
vorm-edit.ng-hide-add,
vorm-display.ng-hide-add {
-webkit-animation: 0.5s flipOutX ease;
animation: 0.5s flipOutX ease;
}
/* when showing the thing */
vorm-edit.ng-hide-remove,
vorm-display.ng-hide-remove {
-webkit-animation: 0.5s flipInX ease;
animation: 0.5s flipInX ease;
position: absolute;
}
vorm-edit > label {
display: flex;
}
input[type="checkbox"] {
margin-right: 5px;
}
/* ANIMATIONS (FROM ANIMATE.CSS) */
/* flip in */
@-webkit-keyframes flipInX {
0% {
-webkit-transform: perspective(400px) rotate3d(1, 0, 0, 180deg);
transform: perspective(400px) rotate3d(1, 0, 0, 180deg);
-webkit-transition-timing-function: ease-in;
transition-timing-function: ease-in;
opacity: 0;
}
100% {
-webkit-transform: perspective(400px) rotate3d(1, 0, 0, 0deg);
transform: perspective(400px) rotate3d(1, 0, 0, 0deg);
opacity: 1;
}
}
@-webkit-keyframes flipOutX {
0% {
-webkit-transform: perspective(400px) rotate3d(1, 0, 0, 180deg);
transform: perspective(400px) rotate3d(1, 0, 0, 180deg);
-webkit-transition-timing-function: ease-in;
transition-timing-function: ease-in;
opacity: 1;
}
100% {
-webkit-transform: perspective(400px) rotate3d(1, 0, 0, 0deg);
transform: perspective(400px) rotate3d(1, 0, 0, 0deg);
opacity: 0;
}
}
@keyframes flipInX {
0% {
-webkit-transform: perspective(400px) rotate3d(1, 0, 0, 180deg);
transform: perspective(400px) rotate3d(1, 0, 0, 180deg);
-webkit-transition-timing-function: ease-in;
transition-timing-function: ease-in;
opacity: 0;
}
100% {
-webkit-transform: perspective(400px) rotate3d(1, 0, 0, 0deg);
transform: perspective(400px) rotate3d(1, 0, 0, 0deg);
opacity: 1;
}
}
@keyframes flipOutX {
0% {
-webkit-transform: perspective(400px) rotate3d(1, 0, 0, 180deg);
transform: perspective(400px) rotate3d(1, 0, 0, 180deg);
-webkit-transition-timing-function: ease-in;
transition-timing-function: ease-in;
opacity: 1;
}
100% {
-webkit-transform: perspective(400px) rotate3d(1, 0, 0, 0deg);
transform: perspective(400px) rotate3d(1, 0, 0, 0deg);
opacity: 0;
}
}
</style>
</head>
<body ng-app="app">
<div class="col-md-6" style="padding: 20px"
form-template>
<form
vorm-form
vorm-submit="ctrl.handleSubmit($values)"
vorm-change="ctrl.handleChange($name)"
ng-controller="FormController as ctrl"
>
<vorm-fieldset class="form-group" fields="ctrl.getFields()">
</vorm-fieldset>
<button class="btn btn-primary" ng-disabled="!vormForm.isValid()" type"submit">
Submit
</button>
</form>
<div style="color: #333; background-color: #f2f2f2; padding: 5px; margin-top: 20px">Open up your console to see some logging.</div>
</div>
<div class="col-md-6">
<pre style="tab-size: 4 !important;padding: 0px !important"><code form class="html"></code></pre>
<pre style="tab-size: 4 !important;padding: 0px !important"><code js></code></pre>
</div>
<script>
void function ( ) {
var script = document.querySelector('script#app'),
tpl = document.querySelector('[form-template]'),
jsCode = document.querySelector('code[js]'),
formCode = document.querySelector('code[form]');
jsCode.textContent = script.textContent;
formCode.textContent = tpl.innerHTML;
hljs.highlightBlock(jsCode);
hljs.highlightBlock(formCode);
}();
</script>
</body>
</html>