blob: 4f22f99238a3ab6f1f45849ae97b035554243aba [file] [log] [blame]
Matteo Scandolo7bc39c42016-04-20 11:38:42 -07001/**
2 * © OpenCORD
3 *
4 * Visit http://guide.xosproject.org/devguide/addview/ for more information
5 *
6 * Created by teone on 4/18/16.
7 */
8
9(function () {
10 'use strict';
11
12 angular.module('xos.uiComponents')
13
14 /**
15 * @ngdoc directive
16 * @name xos.uiComponents.directive:xosForm
17 * @restrict E
18 * @description The xos-form directive
19 * @param {Object} config The configuration object
20 * ```
21 * {
22 * exclude: ['id', 'validators', 'created', 'updated', 'deleted'], //field to be skipped in the form, the provide values are concatenated
23 * actions: [ // define the form buttons with related callback
24 * {
25 label: 'save',
26 icon: 'ok', // refers to bootstraps glyphicon
27 cb: (user) => { // receive the model
28 console.log(user);
29 },
30 class: 'success'
31 }
32 * ]
33 * }
34 * ```
35 * @element ANY
36 * @scope
37 * @example
38 <example module="sampleAlert1">
39 <file name="index.html">
40 <div ng-controller="SampleCtrl1 as vm">
41
42 </div>
43 </file>
44 <file name="script.js">
45 angular.module('sampleAlert1', ['xos.uiComponents'])
46 .controller('SampleCtrl1', function(){
47 this.config1 = {
48 exclude: ['password', 'last_login']
49 };
50 });
51 </file>
52 </example>
53
54 **/
55
56 .directive('xosForm', function(){
57 return {
58 restrict: 'E',
59 scope: {
60 config: '=',
61 ngModel: '='
62 },
63 template: `
64 <ng-form name="vm.config.formName || 'form'">
Matteo Scandolo6e2e6ff2016-04-20 14:59:39 -070065 <div class="form-group" ng-repeat="(name, field) in vm.formField">
Matteo Scandolo9f0e5ae2016-04-20 12:24:52 -070066 <label>{{field.label}}</label>
Matteo Scandolo6e2e6ff2016-04-20 14:59:39 -070067 <input type="{{field.type}}" name="{{name}}" class="form-control" ng-model="vm.ngModel[name]"/>
Matteo Scandolo7bc39c42016-04-20 11:38:42 -070068 </div>
69 <div class="form-group" ng-if="vm.config.actions">
70 <button href=""
71 ng-repeat="action in vm.config.actions"
72 ng-click="action.cb(vm.ngModel)"
73 class="btn btn-{{action.class}}"
74 title="{{action.label}}">
75 <i class="glyphicon glyphicon-{{action.icon}}"></i>
76 {{action.label}}
77 </button>
78 </div>
79 </ng-form>
80 `,
81 bindToController: true,
82 controllerAs: 'vm',
Matteo Scandolo9f0e5ae2016-04-20 12:24:52 -070083 controller: function($scope, $log, _, XosFormHelpers){
Matteo Scandolo7bc39c42016-04-20 11:38:42 -070084
85 if(!this.config){
86 throw new Error('[xosForm] Please provide a configuration via the "config" attribute');
87 }
88
89 if(!this.config.actions){
90 throw new Error('[xosForm] Please provide an action list in the configuration');
91 }
92
Matteo Scandolo7bc39c42016-04-20 11:38:42 -070093 this.excludedField = ['id', 'validators', 'created', 'updated', 'deleted', 'backend_status'];
94 if(this.config && this.config.exclude){
95 this.excludedField = this.excludedField.concat(this.config.exclude);
96 }
97
98
99 this.formField = [];
100 $scope.$watch(() => this.ngModel, (model) => {
101 if(!model){
102 return;
103 }
Matteo Scandolo9f0e5ae2016-04-20 12:24:52 -0700104 this.formField = XosFormHelpers.buildFormStructure(XosFormHelpers.parseModelField(_.difference(Object.keys(model), this.excludedField)), this.config.fields, model);
Matteo Scandolo7bc39c42016-04-20 11:38:42 -0700105 });
106
107 }
108 }
109 })
110 .service('XosFormHelpers', function(_, LabelFormatter){
111
Matteo Scandolo6e2e6ff2016-04-20 14:59:39 -0700112 this._isEmail = (text) => {
113 var re = /(([^<>()[\]\\.,;:\s@\"]+(\.[^<>()[\]\\.,;:\s@\"]+)*)|(\".+\"))@((\[[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\])|(([a-zA-Z\-0-9]+\.)+[a-zA-Z]{2,}))/;
114 return re.test(text);
115 };
116
Matteo Scandolo7bc39c42016-04-20 11:38:42 -0700117 this._getFieldFormat = (value) => {
118
119 // check if is date
Matteo Scandolo9f0e5ae2016-04-20 12:24:52 -0700120 if (_.isDate(value) || (!Number.isNaN(Date.parse(value)) && Date.parse(value) > 0)){
Matteo Scandolo7bc39c42016-04-20 11:38:42 -0700121 return 'date';
122 }
123
124 // check if is boolean
125 // isNaN(false) = false, false is a number (0), true is a number (1)
126 if(typeof value === 'boolean'){
127 return 'boolean';
128 }
129
130 // check if a string is a number
131 if(!isNaN(value)){
132 return 'number';
133 }
134
Matteo Scandolo6e2e6ff2016-04-20 14:59:39 -0700135 // check if a string is an email
136 if(this._isEmail(value)){
137 return 'email';
138 }
139
Matteo Scandolo7bc39c42016-04-20 11:38:42 -0700140 return typeof value;
141 };
142
143 this.buildFormStructure = (modelField, customField, model) => {
144 return _.reduce(Object.keys(modelField), (form, f) => {
145 form[f] = {
146 label: (customField[f] && customField[f].label) ? `${customField[f].label}:` : LabelFormatter.format(f),
147 type: (customField[f] && customField[f].type) ? customField[f].type : this._getFieldFormat(model[f]),
148 validators: {}
149 };
Matteo Scandolo6e2e6ff2016-04-20 14:59:39 -0700150
151 if(form[f].type === 'date'){
152 model[f] = new Date(model[f]);
153 }
154
Matteo Scandolo7bc39c42016-04-20 11:38:42 -0700155 return form;
156 }, {});
157 };
158
159 this.parseModelField = (fields) => {
160 return _.reduce(fields, (form, f) => {
161 form[f] = {};
162 return form;
163 }, {});
164 }
165
166 })
167})();