AngularFormus
AngularFormus copied to clipboard
Form generator for AngularJS
AngularFormus
Customizable and extensible forms generator for AngularJS. License under MIT License.
Usage
Form directive render form by configuration:
<formus-form name="form.name"
model="form.data"
fieldsets="form.fieldsets"
config="form.config">
</formus-form>
Install
$ bower install -S angular-formus
Add a <script> to your index.html:
<script src="/bower_components/angular-formus/dist/formus.min.js"></script>
and add Formus module as dependency to Your application:
angular.module('app', ['formus']);
Form configuration
Example:
form = {
name: "systemParametersForm",
fieldsets: {
fields: [{
"name": "movePayments",
"label": "Move Payments Straight To Cash",
"input": "checkbox"
}, {
"name": "cancelPendingAfter",
"label": "Automatically Cancel Pending Mode Bookings after",
"input": "textbox",
"suffix": "days"
}]
},
config: {
class: 'some-css-class',
submit: {
title: 'Save',
handler: function() {
console.log('I\'m submitted');
}
}
}
}
Field configuration
Form must has one general field, which contain others fields. Example of field declaration:
{
name:'nameOfFieldInModel', // string
label: 'label', // string
fields: [] //array of objects
input:'typeOfInput' // string
}
Fields can contain nested fields.
All field attributes are optional except input.
If attribute name isn't set, that field must contain nested fields (attribute fields).
You can add custom attributes, they are available in view at object config.
Linker can be overriden. E.g:
{
name:'name',
linker:function($scope, $element, $attr, $http /**Some other services**){}
}
Available inputs
- fieldset (container for other fields)
- textbox
- texarea
- select
- checkbox
- radio
- checklist
Customization
Formus supports customization of all module elements.
Templates
To change input template just register it in FormusTemplatesProvider:
app.config(['FormusTemplatesProvider', function (FormusTemplatesProvider) {
FormusTemplatesProvider.setTemplateUrl('color', 'views/formus/inputs/color.html');
FormusTemplatesProvider.setTemplateUrl('group', 'views/formus/inputs/group.html');
FormusTemplatesProvider.setTemplateUrl('file', 'views/formus/inputs/file.html');
FormusTemplatesProvider.setTemplateUrl('gallery', 'views/formus/inputs/gallery.html');
}]);
Validation
Formus supports data validation. Validators can be attached to every field.
{
name: 'title',
input: 'textbox',
validators: {
required: true /** Key - validator name, Value - options **/
}
}
Available validators is contained in FormusValidator service.
Example of adding custom validator:
app.config(['FormusValidatorProvider', function (FormusValidatorProvider) {
FormusValidatorProvider.set('numeric', function (value, config, arg) {
if (value) {
if (!tools.validateNumerical(value)) {
return config.label + ' must be numerical';
}
if (typeof(arg) === 'object') {
if ((angular.isDefined(arg.min)) && (value < arg.min)) {
return config.label + ' must be > ' + arg.min;
}
}
}
return null;
});
}]);
Validator function is called by $injector and has three special parameters:
value- field valueconfig- field configargs- validator options
This validator can take options as object with property min, e.g:
validators: {numeric: {min:0}}
Available validators:
- required
- url
Events
Formus emit an event after validation:
$rootScope.$on('Formus.validatedForm', function(event, name, isValid) {
/*Some stuff*/
});
To validate form without submit:
$rootScope.$broadcast('Formus.validateForm', 'myFormName');
Display back-end errors
For showing errors that return from server you can use attribute errors in formus-form directive.
Errors must be object with properties named as form fields and errors it's array of strings, e.g:
{
name:['Name must be longer']
}
FormusHelper has special method for extracting errors from response.
Example of setting errors:
form.config.submit.handler = function() {
return save().then(function() {
$state.go('^.list');
}).catch(function(response) {
form.errors = FormusHelper.extractBackendErrors(response);
});
};
All methods of FormusHelper can be overridden, e.g:
app.config(['FormusHelperProvider', function(FormusHelperProvider) {
FormusHelperProvider.setMethod('nameOfMethod', function() {
/* Implementation */
});
}]);
Default Configurations
FormusConfig service allows to set default configurations for every type of input.
Setter take two params:
- name of filed
- callback which must return config object
app.config(['FormusConfigProvider', function (FormusConfigProvider) {
FormusConfigProvider.set('datetime', function () {
return {
minView: 0,
startView: 0,
dataType: 'number',
dateFormat: 'shortDate'
}
});
}]);
Features
Nested fields:
You can create form with nested fields:
form = {
fieldsets: {
fields: [
{"name": "val0", "label": "Text Value", "input": "checkbox"},
{"name": "someExtend", "fields": [
{"name": "val1", "label": "Nested Value #1", "input": "textbox"},
{"name": "val2", "label": "Nested Value #2", "input": "select","items": [
{"value":1, "title":"opt 1"},
{"value":2, "title":"opt 2"}
]
},
]
}
]
}
};
As result get model:
{
val0: true,
someExtend:{
val1: 'some text',
val2: 2
}
}
You can use dot notation:
form = {
fieldsets: {
fields: [
{"name": "base.first", "label": "Some Value", "input": "textbox"},
{"name": "base.second", "label": "Some Value#2", "input": "textbox"},
{"name": "other.value", "label": "Some Value#3", "input": "checkbox"},
]
}
};
Result model:
{
base:{
first: 'text val',
first: 'text val2',
},
other:{
value: false
}
}
Forms Container
For comfortable work with large number of forms you can use FormusContainer.
This service provide global storage for form configs.
Configuration:
var formsConfiguration = {form1:{/**...**/}, form2:{/**...**/}};
app.constant('FORMS_CONFIG', formsConfiguration);
app.config(['FormusContainerProvider', 'FORMS_CONFIG', function (FormusContainerProvider, FORMS_CONFIG) {
FormusContainerProvider.setContainer(FORMS_CONFIG);
}]);
After configuration you can use FormusContainer in controller:
var myCtrl = function($scope, FormusContainer){
$scope.form = FormusContainer.get('form1');
}
Default configuration of form can be set using FormusConfig.
app.config(['FormusConfigProvider', function (FormusConfigProvider) {
FormusConfigProvider.set('form', function () {
return {
name: 'default-name',
fieldset: { fields: [] },
data: {},
config: {
buttons: [],
submit: { title: 'Save', handler: function() {} }
}
}
});
}]);
To extend a form configuration you can specify attribute parent. Formus will search container for form with that name and use its configuration.
{
//form containter
parent: {
config:{
submit:{title:'Find'}
}
},
child: {
parent:'parent'
}
}
Linkers
You can set custom linkers for special input types:
app.config(['FormusLinkerProvider', function (FormusLinkerProvider) {
FormusLinkerProvider.setLinker('gallery', function ($scope, $element, fileUpload) {
$scope.uploadImage = function () {
if (fileUpload.isValid($element.find('.imgFileInput'))) {
alert('Select file');
} else {
fileUpload.upload($element.find('.imgFileInput')).then(function (response) {
$scope.model.push(response.data.url);
});
}
};
$scope.removeImage = function (index) {
$scope.model.splice(index, 1);
};
$scope.afterLoadTemplate = function () {
if (!Array.isArray($scope.model)) {
$scope.model = [];
}
}
});
}]);
Wrapper
Every field in form is wrapped in special directive, it name formusWrapper.
Is possible to override it template by using FormusTemplates service:
app.config(['FormusTemplatesProvider', function (FormusTemplatesProvider) {
FormusTemplatesProvider.setTemplateUrl('wrapper', 'views/formus/inputs/my-custm-wrapper.html');
}]);