Breaking change on version 0.9.0:
- In order to match select2 format the
itemsprop ofvf-select(andvf-button-list) now recieves objects with the following format:{id:1, text:'Option A'}, instead of{value:1, text:'Option A'} - The
select2prop ofvf-selectis now a boolean. Options should be passed through the newoptionsprop.
This vue.js package offers a comperhensive solution for HTML form management, including presentation, validation and (optional) AJAX submission. The presentation is based on Bootstrap's form component.
- Vue.js (>=1.0)
- Bootstrap (CSS)
- vue-resource (>=0.9.0) (When submitting via AJAX)
Compilation requires browserify with stringify or webpack with html-loader.
npm install vue-formular
Require the script:
var VueFormular = require('vue-formular');
Import the standalone compiled script
Vue.use(VueFormular, options);
For example:
<vf-form action="process-form" method="POST" :validation="validation" :options="options">
<vf-status-bar></vf-status-bar>
<vf-text label="User name:" name="username"></vf-text>
<vf-password label="Password:" name="password"></vf-password>
<vf-submit></vf-submit>
</vf-form>
By default the form is sent through as a normal synchronous request. Other options are (add as props to vf-form):
ajax- Send async request. requiresvue-resourceclient- Form is not sent to the server. To fetch the data listen for thevue-formular.sentevent.
Another optional prop for the form is triggers. It is used to specify fields whose display depends on the values of other fields.
The syntax is similar to that of the validation rules requiredIf and requiredAndShownIf:
{
triggeredFieldName:'triggeringField:value1,value2'
}
To trigger with any truthy value simply omit the values list.
Fields can be used in a form as direct vue children of the form, or independently (see the change event).
All fields accept the following properties:
labelstringoptionalnamestringrequiredfield's identifiervaluemixedoptionaldisabledbooleanoptional
The following fields are supported:
-
vf-text-input[type=text] -
vf-number-input[type=number] -
vf-password-input[type=password] -
vf-email-input[type=email] -
vf-textarea- long texttinymceobject\booleanoptionalUse tinymce editor (>=4.0). Accepts options for tinymce, or nothing.
All of the above accept optional placeholder prop.
All of the above have a debounce prop, which defaults to 300ms.
Numeric and email fields will be validated accordingly.
-
vf-date- Datepicker (single or range).uses daterangepicker. the
valueshould be passed as a string, matching the 'YYYY-MM-DD HH:mm:ss' format, or as a moment object. The date will be sent to the server usingmoment's format method (ISO 8601)rangebooleanoptionalpick a range of dates. thevalueprop should be passed as an object withstartandendproperties. A similar object is sent to the serverformatstringoptionalDate presentation (usingmoment). Default: 'DD/MM/YYYY'.optionsobjectoptionalPlugin options. Merged with the form-level optiondateOptions.clearLabelstringoptionalLabel for clearing current date. Default: 'Clear'
-
vf-select- select listselect2booleanoptionalUse select2 (4.0.0 Only)optionsobjectoptionalSelect2 optionscontainer-classstringoptionalWhen using select2, use this to set a class for the container and the dropdown. The class will be preceded by the entity (e.gmodalwould generatedropdown-modalandcontainer-modal)multiplebooleanoptionalitemsarray of objectsoptional- item format:{id:1, text:'Option A'}. Defaults to an empty arrayplaceholderstringDefault option text (value will be an empty string). Default: 'Select Option'. Displayed only for a single select, which is not a select2.no-defaultbooleanoptionalDon't display the default optionajax-urlstringoptionalFetch options from remote server using this url.selectedarray of objectsoptionalwhen using ajax, use this option to pre-populate the list with selected value(s). Syntax is the same asitemscallbackfunctionoptionalWhen usingajax-urlthis can be used to process the raw server output before it is passed to presentation.filter-bystringoptionalDynamically filter list options by another select field. Recieves the name of the other field. The list items should each have a key with the same name, whose value will be compared against the filtering field's value. When the filtering field has no value all items are presented. When the list is fetched remotely the filtering field value is sent as a request parameter Note: Due to issues with dynamically updating data passed to select2 on v4.0.0 (select2/select2#2830), This option will currently not work on aselect2with local data (i.e it will work on a noraml select or select2 withajax-url).
-
vf-checkbox- a single boolean checkboxcheckedbooleanuse this instead ofvalue
-
vf-buttons-list- list of radio\checkbox buttonsmultiplebooleanoptionalitemssame as invf-select
-
vf-file-ajaxbooleanoptional- use JQuery File Upload. File rules will be sent as a stringifiedruleskey.optionsobjectoptional- plugin options for this field. merged with thefileOptionsform-level option.
-
vf-submit- Submit button. Will be disabled when the form is in pristine state ifsendOnlyDirtyFieldsis set totruetextstringoptionalButton text. Default: 'Submit'
Note: All fields share a fieldType property which can be programatically used to determine the type of the component.
All fields have beforeField and afterField slots, which allow you to add custom HTML.
There are two ways to pass rules:
a. Through the form's validation prop.
b. Through the rules prop of each individual field.
Rules which depend on other fields (i.e requiredIf,greaterThan and smallerThan) should be passed using option a.
Option a example:
{
rules: {
username: {
required:true,
min: 6
},
password: {
required:true
}
},
messages:{
username: {
required:"custom message for :field"
}
}
}
The optional messages property overides the default messages object for a specific field.
Option b example:
<vf-text label="Username:" name="username" :rules="{required:true, min:6}"></vf-text>
Supported rules:
-
requiredbooleanrequired fields will be given a unique class you can use to mark the field as required. E.g:.VF-Field--required label { position: relative; } .VF-Field--required>label:before { content:"*"; font-size: 20px; color:red; position: absolute; left:-15px; } -
requiredIfstring- make the field required only if another field was filled with a value (typically a select or checkbox). The field would only display when required. To set specific values for requiring the field use the following format:otherField:val1, val2 -
requiredAndShownIfstring- same asrequiredIf, excecpt that the field also is hidden when it is not required. -
emailboolean- Automatically set totrueforvf-email -
numberboolean- Automatically set totrueforvf-number -
min,max,betweennumber- a. If thenumberorintegerrules are set totruevalidates numeric values b. If the parameter is amomentobject or aYYYY-MM-DD-formatted string validates dates c. Otherwise - validates string length -
integerboolean -
digitsboolean -
remotestringValidate field on the server end. Accepts a url, to which the value is sent on change event as a request parameter. Requiresvue-resource -
greaterThan,smallerThanstringaccepts the name of the compared field. Compares numbers and dates -
urlboolean
To create your own custom rule(s) pass a customRules property to the form's options.
the rules are passed as a function that returns true if validation passes. e.g:
customRules: {
someRule: function(field) {
return field.value=='something'
}
}
You can set the default message for the rule, and also override other default messages, by passing a messages property to the options object. Defaults are:
{
required:'The :field field is required',
number:'The :field field must be a number',
integer:'The :field field must be an integer',
digits:'The :field field must have digits only',
email:'The :field field must be a valid email address',
between:{
string:'The field :field must contain between {0} and {1} characters',
number:'The field :field must be a number between {0} and {1}',
date:'The field :field must be a date between {0} and {1}'
},
min: {
string:'The :field field must contain at least {0} characters',
number:'The :field field must be equal to or greater than {0}',
date:'The field :field must be a date equal to or greater than {0}'
},
max: {
string:'The field :field must contain no more than {0} characters',
number:'The field :field must be equal to or smaller than {0}',
date:'The field :field must be a date equal to or smaller than {0}'
},
remote:'Remote Error',
requiredIf:'The field :field is required',
url:'Please enter a valid URL',
greaterThan:'The field :field must be greater than :relatedField',
smallerThan:'The field :field must be smaller than :relatedField'
}
Sometimes you might want to do some extra validation on the server side, after the form is sent (i.e no client-side validation errors). If server-side validation fails simply return some invalid code (e.g 400). The response content will be displayed in the status bar. To display more than one error, return an array similar to this:
[
{
name: 'username',
message: 'The username field is required'
},
{
name: 'password',
message: 'The password must contain at least 6 characters'
}
]
Field methods can be called by applying a v-ref to the field and fetching it from the $refs object.
setValue(value)Programatically set a value on a field. The view will be updated accordingly.focus()
vue-formular.sending (ajax form)
Fires off when the form is being sent. A message will automatically appear in the status bar.
vue-formular.sent (ajax form)
Fires off after the form has been sent successfully. Sends through the form data. The status bar will show the response returned from the server, if it is a string, or else the designtaed text.
vue-formular.invalid.client
Fires off after form submission was prevented due to client-side errors. Sends through the errors
vue-formular.invalid.server (ajax form)
Fires off after the form returned an invalid response from the server. Sends through the response
vue-formular.change::field_name
Fires off whenever a field's value is changed. Send through the new and old values. This allows for using fields independently of the form.
vue-formular.change
Global change event. Sends through the name of the changed field, in addition to the old and new values
vue-formular.clicked-error
Fires off when the user clicked one of the error links in the statusbar. Sends through the clicked field name.
Here is how you can go about creating new types of fields. Let's create a time range picker.
Start by creating a timerange.html HTML template:
<div class="timerangepicker">
<div class="time-select">
<label for="from">From</label>
<select name="from" v-model="from">
<option value="Select Time"></option>
<option v-for="time in times" value="{{time}}">{{time}}</option>
</select>
</div>
<div class="time-select">
<label for="to">To</label>
<select name="to" v-model="to">
<option value="Select Time"></option>
<option v-for="time in times" value="{{time}}">{{time}}</option>
</select>
</div>
</div>
Then create a timerange.js file:
var merge = require('merge');
var Field = require('vue-formular/lib/components/fields/field');
module.exports = function() {
return merge.recursive(Field(), {
data:function() {
return {
fieldType:'timerange',
times: getTimes(),
from:'',
to:''
}
},
ready: function() {
this.$set('rules.timerange', true);
},
computed: {
value: function() {
if (!this.from || !this.to) return '';
return this.from + '-' + this.to;
}
}
});
}
function getTimes() {
var times = [];
for (var i=0; i<24; i++) {
for (var j=0; j<60; j = j+30) {
times.push(('0' + i).slice(-2) + ":" + ('0' + j).slice(-2));
}
}
return times;
}
Note that we extend the main abstract field component, and name the fieldType property with the same name as the partial we are about to register.
Now, let's add the timerange rule to prevent an invalid range:
customRules: {
timerange: function(field) {
if (!field.value) return true;
var pieces = field.value.split('-');
pieces = pieces.map(function(piece) {
return parseInt(piece.replace(':',''));
});
return pieces[1]>pieces[0];
}
}
Lastly, register the component and the partial:
Vue.component('vf-timerange', require('./timerange')());
Vue.partial('timerange', require('./timerange.html'));
Note: if you are sending the form using a normal request (i.e not ajax or client-only), you need to add a hidden field to the template which will recieve the value.
You can find an example in the date component (date.html)
Options are set in three layers, where the more particular overrides the more general.
- Pre-defined defaults.
- User-defined defaults for the global Vue Instance. Passed as the second paramter to the
Usestatement. - Options for a single form, passed through the
optionsprop.
-
layoutstringBootstrap's form layout class. Defaults to a vertical block display. other options areform-horizontalandform-inlineWhen using a layout other thanform-horizontaladjust thetoprule of theform-control-feedbackclass to get the feedback icon aligned with the field. -
labelWidthnumberrelevant only for horizontal layout. The number of grid columns allocated for the label. Defaults to3. -
showClientErrorsInStatusBarbooleanShow client errors in the status bar, with links to the relevant fields, in addition to the error shown under each field. Useful for long forms. Deault:false -
additionalPayloadobjectCustom data you want to send along with the form. Serves a similar purpose to that of a hidden input field -
sendOnlyDirtyFieldsbooleanwhen using AJAX form send only the dirty fields. Default:false -
select2Optionsobject- Global options for select2, to be used on 'vf-select' with a 'select2' or 'ajax-url' prop -
tinymceOptionsobject- Global options for tinymce. To be used on avf-textareafield with atinymceprop. -
fileOptionsobject- Global options for JQuery File Upload, to be used onvf-filewith anajaxprop. -
dateOptionsobject- Global options for daterangepicker, to be used onvf-date. -
successTimeoutnumber- Time in ms before hiding the success message after the form was sent using AJAX. Default: 4000 -
customRulesobjectSee above -
messagesobjectsee above -
textsobjectDefault:{ sending:'Sending Form...', sent:'Form was successfully sent', // this will be presented in case a string is not returned from the server singleError:'an error was found:', // status bar errors list title errors:'{0} errors were found:' }