blob: 185abc3e9fd98708d9d10a477e6f59ce190bd0e7 [file] [log] [blame]
Matteo Scandoloa5d03d52016-07-21 11:35:46 -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
13 angular.module('xos.uiComponents')
14
15 /**
16 * @ngdoc directive
17 * @name xos.uiComponents.directive:xosForm
18 * @restrict E
19 * @description The xos-form directive.
20 * This components have two usage, given a model it is able to autogenerate a form or it can be configured to create a custom form.
21 * @param {Object} config The configuration object
22 * ```
23 * {
24 * exclude: ['id', 'validators', 'created', 'updated', 'deleted'], //field to be skipped in the form, the provide values are concatenated
Matteo Scandolobfb8ebd2016-10-28 17:53:05 +020025 * order: ['field1', 'field2'], // ordering the fields (missing ones are attached at the end)
Matteo Scandoloa5d03d52016-07-21 11:35:46 -070026 * actions: [ // define the form buttons with related callback
27 * {
28 label: 'save',
29 icon: 'ok', // refers to bootstraps glyphicon
30 cb: (user) => { // receive the model
31 console.log(user);
32 },
33 class: 'success'
34 }
35 * ],
36 * feedback: {
37 show: false,
38 message: 'Form submitted successfully !!!',
39 type: 'success' //refers to bootstrap class
40 },
41 * fields: {
42 * field_name: {
43 * label: 'Field Label',
44 * type: 'string' // options are: [date, boolean, number, email, string, select],
45 * validators: {
46 * minlength: number,
47 maxlength: number,
48 required: boolean,
49 min: number,
50 max: number,
51 custom: (value) => {
52 // do your validation here and return true | false
53 // alternatively you can return an array [errorName, true|false]
54 }
55 * }
56 * }
57 * }
58 * }
59 * ```
Matteo Scandolobfb8ebd2016-10-28 17:53:05 +020060 * @param {Object} ngModel The model object (it is mandatory to specify at least an empty object)
Matteo Scandoloa5d03d52016-07-21 11:35:46 -070061 * @element ANY
62 * @scope
63 * @requires xos.uiComponents.directive:xosField
64 * @requires xos.uiComponents.XosFormHelpers
65 * @requires xos.helpers._
66 * @example
Steven Burrows84818482016-09-29 15:33:46 -070067
Matteo Scandoloa5d03d52016-07-21 11:35:46 -070068 Autogenerated form
69
70 <example module="sampleForm">
71 <file name="script.js">
72 angular.module('sampleForm', ['xos.uiComponents'])
73 .factory('_', function($window){
74 return $window._;
75 })
76 .controller('SampleCtrl', function(){
77 this.model = {
78 first_name: 'Jhon',
79 last_name: 'Doe',
80 email: 'jhon.doe@sample.com',
81 active: true,
82 birthDate: '2015-02-17T22:06:38.059000Z'
83 }
84 this.config = {
85 exclude: ['password', 'last_login'],
86 formName: 'sampleForm',
87 actions: [
88 {
89 label: 'Save',
90 icon: 'ok', // refers to bootstraps glyphicon
91 cb: (user) => { // receive the model
92 console.log(user);
93 },
94 class: 'success'
95 }
96 ]
97 };
98 });
99 </file>
100 <file name="index.html">
101 <div ng-controller="SampleCtrl as vm">
102 <xos-form ng-model="vm.model" config="vm.config"></xos-form>
103 </div>
104 </file>
105 </example>
106
107 Configuration defined form
108
109 <example module="sampleForm1">
110 <file name="script.js">
111 angular.module('sampleForm1', ['xos.uiComponents','ngResource', 'ngMockE2E'])
112 .factory('_', function($window){
113 return $window._;
114 })
115 .controller('SampleCtrl1', function(SampleResource){
116
Matteo Scandolobfb8ebd2016-10-28 17:53:05 +0200117 this.model = {};
Matteo Scandoloa5d03d52016-07-21 11:35:46 -0700118
119 this.config = {
120 exclude: ['password', 'last_login'],
121 formName: 'sampleForm1',
122 feedback: {
123 show: false,
Matteo Scandolobfb8ebd2016-10-28 17:53:05 +0200124 message: 'Form submitted successfully!',
Matteo Scandoloa5d03d52016-07-21 11:35:46 -0700125 type: 'success'
126 },
127 actions: [
128 {
129 label: 'Save',
Matteo Scandolobfb8ebd2016-10-28 17:53:05 +0200130 icon: 'ok',
131 cb: (user) => {
Matteo Scandoloa5d03d52016-07-21 11:35:46 -0700132 console.log(user);
133 this.config.feedback.show = true;
134 this.config.feedback.type='success';
135 },
136 class: 'success'
137 }
138 ],
Matteo Scandolobfb8ebd2016-10-28 17:53:05 +0200139 order: ['site', 'last_name', 'first_name', 'age'],
Matteo Scandoloa5d03d52016-07-21 11:35:46 -0700140 fields: {
141 first_name: {
142 type: 'string',
143 validators: {
144 required: true
145 }
146 },
147 last_name: {
148 label: 'Surname',
149 type: 'string',
150 validators: {
151 required: true,
152 minlength: 10
153 }
154 },
155 age: {
156 type: 'number',
157 validators: {
158 required: true,
159 min: 21
160 }
161 },
Matteo Scandoloa5d03d52016-07-21 11:35:46 -0700162 site: {
Matteo Scandolobfb8ebd2016-10-28 17:53:05 +0200163 label: 'Site',
164 type: 'select',
165 validators: { required: true},
166 hint: 'The Site this Slice belongs to',
167 options: []
Matteo Scandoloa5d03d52016-07-21 11:35:46 -0700168 },
169 }
170 };
171 SampleResource.query().$promise
Matteo Scandolobfb8ebd2016-10-28 17:53:05 +0200172 .then((users) => {
Matteo Scandoloa5d03d52016-07-21 11:35:46 -0700173 this.optionVal = users;
174 this.config.fields['site'].options = this.optionVal;
Matteo Scandolobfb8ebd2016-10-28 17:53:05 +0200175 })
176 .catch((e) => {
177 throw new Error(e);
178 });
Matteo Scandoloa5d03d52016-07-21 11:35:46 -0700179 });
180 </file>
181 <file name="backend.js">
182 angular.module('sampleForm1')
183 .run(function($httpBackend, _){
184 let datas = [{id: 1, label: 'site1'},{id: 4, label: 'site4'},{id: 3, label: 'site3'}];
185 let paramsUrl = new RegExp(/\/test\/(.+)/);
186 $httpBackend.whenGET('/test').respond(200, datas)
187 })
188 .service('SampleResource', function($resource){
189 return $resource('/test/:id', {id: '@id'});
190 });
Matteo Scandoloa5d03d52016-07-21 11:35:46 -0700191 </file>
192 <file name="index.html">
193 <div ng-controller="SampleCtrl1 as vm">
194 <xos-form ng-model="vm.model" config="vm.config"></xos-form>
195 </div>
196 </file>
197 </example>
198
199 **/
200
Arpit Agarwal34b63832016-08-08 11:59:45 -0700201 .component('xosForm', {
202 restrict: 'E',
203 bindings: {
204 config: '=',
205 ngModel: '='
206 },
207 template: `
208 <form name="vm.{{vm.config.formName || 'form'}}" novalidate>
209 <div class="form-group" ng-repeat="(name, field) in vm.formField">
210 <xos-field name="name" field="field" ng-model="vm.ngModel[name]"></xos-field>
211 <xos-validation field="vm[vm.config.formName || 'form'][name]" form = "vm[vm.config.formName || 'form']"></xos-validation>
212 <div class="alert alert-info" ng-show="(field.hint).length >0" role="alert">{{field.hint}}</div>
213 </div>
214 <div class="form-group" ng-if="vm.config.actions">
215 <xos-alert config="vm.config.feedback" show="vm.config.feedback.show">{{vm.config.feedback.message}}</xos-alert>
Matteo Scandoloa5d03d52016-07-21 11:35:46 -0700216
Arpit Agarwal34b63832016-08-08 11:59:45 -0700217 <button role="button" href=""
218 ng-repeat="action in vm.config.actions"
219 ng-click="action.cb(vm.ngModel, vm[vm.config.formName || 'form'])"
220 class="btn btn-{{action.class}}"
221 title="{{action.label}}">
222 <i class="glyphicon glyphicon-{{action.icon}}"></i>
223 {{action.label}}
224 </button>
225 </div>
226 </form>
227 `,
228 bindToController: true,
229 controllerAs: 'vm',
230 controller: function($scope, $log, _, XosFormHelpers){
Matteo Scandoloa5d03d52016-07-21 11:35:46 -0700231
Arpit Agarwal34b63832016-08-08 11:59:45 -0700232 if(!this.config){
233 throw new Error('[xosForm] Please provide a configuration via the "config" attribute');
Matteo Scandoloa5d03d52016-07-21 11:35:46 -0700234 }
Arpit Agarwal34b63832016-08-08 11:59:45 -0700235
236 if(!this.config.actions){
237 throw new Error('[xosForm] Please provide an action list in the configuration');
238 }
239
240 if(!this.config.feedback){
241 this.config.feedback = {
242 show: false,
243 message: 'Form submitted successfully !!!',
244 type: 'success'
245 }
246 }
247
248 this.excludedField = ['id', 'validators', 'created', 'updated', 'deleted', 'backend_status'];
249 if(this.config && this.config.exclude){
250 this.excludedField = this.excludedField.concat(this.config.exclude);
251 }
252
253 this.formField = [];
254
255 $scope.$watch(() => this.config, ()=> {
256 if(!this.ngModel){
257 return;
258 }
259 let diff = _.difference(Object.keys(this.ngModel), this.excludedField);
260 let modelField = XosFormHelpers.parseModelField(diff);
Matteo Scandolobfb8ebd2016-10-28 17:53:05 +0200261 this.formField = XosFormHelpers.buildFormStructure(modelField, this.config.fields, this.ngModel, this.config.order);
Arpit Agarwal34b63832016-08-08 11:59:45 -0700262 }, true);
263
264 $scope.$watch(() => this.ngModel, (model) => {
265 // empty from old stuff
266 this.formField = {};
267 if(!model){
268 return;
269 }
270 let diff = _.difference(Object.keys(model), this.excludedField);
271 let modelField = XosFormHelpers.parseModelField(diff);
Steven Burrows84818482016-09-29 15:33:46 -0700272 this.formField = XosFormHelpers.buildFormStructure(modelField, this.config.fields, model, this.config.order);
Arpit Agarwal34b63832016-08-08 11:59:45 -0700273 });
274
Matteo Scandoloa5d03d52016-07-21 11:35:46 -0700275 }
276 });
277})();