blob: a20422292f9eff3a9ea426e48f1c964c245bf2bb [file] [log] [blame]
Matteo Scandolo686547a2017-08-08 13:05:25 -07001
2/*
3 * Copyright 2017-present Open Networking Foundation
4
5 * Licensed under the Apache License, Version 2.0 (the "License");
6 * you may not use this file except in compliance with the License.
7 * You may obtain a copy of the License at
8
9 * http://www.apache.org/licenses/LICENSE-2.0
10
11 * Unless required by applicable law or agreed to in writing, software
12 * distributed under the License is distributed on an "AS IS" BASIS,
13 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 * See the License for the specific language governing permissions and
15 * limitations under the License.
16 */
17
18
Matteo Scandoloa5d03d52016-07-21 11:35:46 -070019/**
20 * © OpenCORD
21 *
22 * Visit http://guide.xosproject.org/devguide/addview/ for more information
23 *
24 * Created by teone on 5/25/16.
25 */
26
27(function () {
28 'use strict';
29
30 angular.module('xos.uiComponents')
31 /**
32 * @ngdoc directive
33 * @name xos.uiComponents.directive:xosField
34 * @restrict E
35 * @description The xos-field directive.
36 * This component decide, give a field wich kind of input it need to print.
37 * @param {string} name The field name
38 * @param {object} field The field configuration:
39 * ```
40 * {
41 * label: 'Label',
42 * type: 'number', //typeof field
43 * validators: {} // see xosForm for more details
44 * }
45 * ```
46 * @param {mixed} ngModel The field value
47 *
48 * @example
49
50 # Basic Example
51
52 <example module="sampleField1">
53 <file name="script.js">
54 angular.module('sampleField1', ['xos.uiComponents'])
55 .factory('_', function($window){
56 return $window._;
57 })
58 .controller('SampleCtrl', function(){
59 this.name = 'input-name';
60 this.field = {label: 'My String Value:', type: 'string'};
61 this.model = 'my string';
62 });
63 </file>
64 <file name="index.html">
65 <div ng-controller="SampleCtrl as vm">
66 <xos-field ng-model="vm.model" name="vm.name" field="vm.field"></xos-field>
67 </div>
68 </file>
69 </example>
70
71 # Possible Values
72
73 <example module="sampleField2">
74 <file name="script.js">
75 angular.module('sampleField2', ['xos.uiComponents'])
76 .factory('_', function($window){
77 return $window._;
78 })
79 .controller('SampleCtrl', function(){
80 this.field1 = {
81 name: 'number-field',
82 field: {label: 'My Number Value:', type: 'number'},
83 model: 2
84 };
85
86 this.field2 = {
87 name: 'date-field',
88 field: {label: 'My Date Value:', type: 'date'},
89 model: new Date()
90 };
91
92 this.field3 = {
93 name: 'boolean-field',
94 field: {label: 'My Boolean Value:', type: 'boolean'},
95 model: true
96 };
97
98 this.field4 = {
99 name: 'email-field',
100 field: {label: 'My Email Value:', type: 'email'},
101 model: 'sample@domain.us'
102 };
Matteo Scandolo65116c42016-09-21 17:06:23 -0700103
104 this.field5 = {
105 name: 'select',
Matteo Scandolobfb8ebd2016-10-28 17:53:05 +0200106 field: {
107 label: 'Select field:',
108 type: 'select',
109 options: [
110 {id: 1, label: 'One'},
111 {id: 2, label: 'Two'},
112 {id: 3, label: 'Three'},
113 ]
114 },
115 model: 1
116 };
117
118 this.arrayField = {
119 name: 'array',
120 field: {
121 label: 'Array field:',
122 type: 'array',
123 options: ['one', 'two', 'three', 'four']
124 },
125 model: ['one', 'two'],
Matteo Scandolo65116c42016-09-21 17:06:23 -0700126 };
Matteo Scandoloa5d03d52016-07-21 11:35:46 -0700127 });
128 </file>
129 <file name="index.html">
130 <div ng-controller="SampleCtrl as vm">
131 <xos-field ng-model="vm.field1.model" name="vm.field1.name" field="vm.field1.field"></xos-field>
132 <xos-field ng-model="vm.field2.model" name="vm.field2.name" field="vm.field2.field"></xos-field>
133 <xos-field ng-model="vm.field3.model" name="vm.field3.name" field="vm.field3.field"></xos-field>
134 <xos-field ng-model="vm.field4.model" name="vm.field4.name" field="vm.field4.field"></xos-field>
Matteo Scandolo65116c42016-09-21 17:06:23 -0700135 <xos-field ng-model="vm.field5.model" name="vm.field5.name" field="vm.field5.field"></xos-field>
Matteo Scandolobfb8ebd2016-10-28 17:53:05 +0200136 <xos-field ng-model="vm.arrayField.model" name="vm.arrayField.name" field="vm.arrayField.field"></xos-field>
Matteo Scandoloa5d03d52016-07-21 11:35:46 -0700137 </div>
138 </file>
139 </example>
140
141 # This element is recursive
142
143 <example module="sampleField3">
144 <file name="script.js">
145 angular.module('sampleField3', ['xos.uiComponents'])
146 .factory('_', function($window){
147 return $window._;
148 })
149 .controller('SampleCtrl', function(){
150 this.name1 = 'input-name';
151 this.field1 = {label: 'My Object Field:', type: 'object'};
152 this.model1 = {
153 name: 'Jhon',
154 age: '25',
155 email: 'jhon@thewall.ru',
156 active: true
157 };
158
159 this.name2 = 'another-name';
160 this.field2 = {
161 label: 'Empty Object Field',
162 type: 'object',
163 properties: {
164 foo: {
165 label: 'FooLabel:',
166 type: 'string',
167 validators: {
168 required: true
169 }
170 },
171 bar: {
172 type: 'number'
173 }
174 }
175 }
176 });
177 </file>
178 <file name="index.html">
179 <div ng-controller="SampleCtrl as vm">
180 <h4>Autogenerated object field</h4>
181 <xos-field ng-model="vm.model1" name="vm.name1" field="vm.field1"></xos-field>
182
183 <h4>Configured object field</h4>
184 <xos-field ng-model="vm.model2" name="vm.name2" field="vm.field2"></xos-field>
185 </div>
186 </file>
187 </example>
188 */
Arpit Agarwal34b63832016-08-08 11:59:45 -0700189 .component('xosField', {
190 restrict: 'E',
191 bindings: {
192 name: '=',
193 field: '=',
194 ngModel: '='
195 },
196 template: `
Matteo Scandolo65116c42016-09-21 17:06:23 -0700197 <label ng-if="vm.field.type !== 'object' && vm.field.type !== 'array'">{{vm.field.label}}</label>
198 <input
199 xos-custom-validator custom-validator="vm.field.validators.custom || null"
200 ng-if="vm.field.type !== 'boolean' && vm.field.type !== 'object' && vm.field.type !== 'select' && vm.field.type !== 'array'"
201 type="{{vm.field.type}}"
202 name="{{vm.name}}"
203 class="form-control"
204 ng-model="vm.ngModel"
205 ng-minlength="vm.field.validators.minlength || 0"
206 ng-maxlength="vm.field.validators.maxlength || 2000"
207 ng-required="vm.field.validators.required || false" />
208 <select class="form-control" ng-if ="vm.field.type === 'select'"
209 name = "{{vm.name}}"
210 ng-options="item.id as item.label for item in vm.field.options"
211 ng-model="vm.ngModel"
212 ng-required="vm.field.validators.required || false">
213 </select>
214 <span class="boolean-field" ng-if="vm.field.type === 'boolean'">
215 <a href="#"
216 class="btn btn-success"
217 ng-show="vm.ngModel"
218 ng-click="vm.ngModel = false">
219 <i class="glyphicon glyphicon-ok"></i>
220 </a>
221 <a href="#"
222 class="btn btn-danger"
223 ng-show="!vm.ngModel"
224 ng-click="vm.ngModel = true">
225 <i class="glyphicon glyphicon-remove"></i>
226 </a>
227 </span>
228 <div
229 class="panel panel-default object-field"
230 ng-if="vm.field.type == 'object' && (!vm.isEmptyObject(vm.ngModel) || !vm.isEmptyObject(vm.field.properties))"
231 >
232 <div class="panel-heading">{{vm.field.label}}</div>
233 <div class="panel-body">
234 <div ng-if="!vm.field.properties" ng-repeat="(k, v) in vm.ngModel">
235 <xos-field
236 name="k"
237 field="{label: vm.formatLabel(k), type: vm.getType(v)}"
238 ng-model="v">
239 </xos-field>
Arpit Agarwal34b63832016-08-08 11:59:45 -0700240 </div>
Matteo Scandolo65116c42016-09-21 17:06:23 -0700241 <div ng-if="vm.field.properties" ng-repeat="(k, v) in vm.field.properties">
242 <xos-field
243 name="k"
244 field="{
245 label: v.label || vm.formatLabel(k),
246 type: v.type,
247 validators: v.validators
248 }"
249 ng-model="vm.ngModel[k]">
250 </xos-field>
251 </div>
252 </div>
253 </div>
254 <div
255 class="panel panel-default array-field"
256 ng-if="vm.field.type == 'array'">
257 <div class="panel-heading">{{vm.field.label}}</div>
258 <div class="panel-body selected">
259 <ul class="draggable" dnd-list="vm.ngModel">
260 <li
261 class="array-element"
262 ng-repeat="item in vm.ngModel"
263 dnd-draggable="item"
264 dnd-moved="vm.ngModel.splice($index, 1)"
265 dnd-effect-allowed="move"
266 dnd-selected="models.selected = item"
267 >
268 <div class="well well-sm text-center">
269 {{item}}
270 </div>
271 </li>
272 <div class="clearfix"></div>
273 </ul>
274 </div>
275 <div class="panel-body unselected">
276 <ul class="draggable" dnd-list="vm.field.availableOptions">
277 <li
278 class="array-element"
279 ng-repeat="item in vm.field.availableOptions"
280 dnd-draggable="item"
281 dnd-moved="vm.field.availableOptions.splice($index, 1)"
282 dnd-effect-allowed="move"
283 dnd-selected="models.selected = item"
284 >
285 <div class="well well-sm text-center">
286 {{item}}
287 </div>
288 </li>
289 <div class="clearfix"></div>
290 </ul>
291 </div>
292 </div>
Arpit Agarwal34b63832016-08-08 11:59:45 -0700293 `,
294 bindToController: true,
295 controllerAs: 'vm',
Matteo Scandolo65116c42016-09-21 17:06:23 -0700296 controller: function($attrs, $scope, XosFormHelpers, LabelFormatter, _){
Matteo Scandoloa5d03d52016-07-21 11:35:46 -0700297
Arpit Agarwal34b63832016-08-08 11:59:45 -0700298 if(!this.name){
299 throw new Error('[xosField] Please provide a field name');
Matteo Scandoloa5d03d52016-07-21 11:35:46 -0700300 }
Arpit Agarwal34b63832016-08-08 11:59:45 -0700301 if(!this.field){
302 throw new Error('[xosField] Please provide a field definition');
303 }
304 if(!this.field.type){
305 throw new Error('[xosField] Please provide a type in the field definition');
306 }
307 if(!$attrs.ngModel){
308 throw new Error('[xosField] Please provide an ng-model');
309 }
310 this.getType = XosFormHelpers._getFieldFormat;
311 this.formatLabel = LabelFormatter.format;
312
313 this.isEmptyObject = o => o ? Object.keys(o).length === 0 : true;
Matteo Scandolo65116c42016-09-21 17:06:23 -0700314
315 if(this.field.type === 'array'){
316 $scope.$watch(() => this.ngModel.length, () => {
317 this.field.availableOptions = _.difference(this.field.options, this.ngModel);
318 });
319 }
320
Matteo Scandoloa5d03d52016-07-21 11:35:46 -0700321 }
322 })
323
324/**
325 * @ngdoc directive
326 * @name xos.uiComponents.directive:xosCustomValidator
327 * @restrict A
328 * @description The xosCustomValidator directive.
329 * This component apply a custom validation function
330 * @param {function} customValidator The function that execute the validation.
331 *
332 * You should do your validation here and return true | false,
333 * or alternatively you can return an array [errorName, true|false]
334 */
335 .directive('xosCustomValidator', function(){
336 return {
337 restrict: 'A',
338 scope: {
339 fn: '=customValidator'
340 },
341 require: 'ngModel',
342 link: function(scope, element, attr, ctrl){
343 if(!angular.isFunction(scope.fn)){
344 return;
345 }
346
347 function customValidatorWrapper(ngModelValue) {
348 const valid = scope.fn(ngModelValue);
349 if(angular.isArray(valid)){
350 // ES6 spread rocks over fn.apply()
351 ctrl.$setValidity(...valid);
352 }
353 else{
354 ctrl.$setValidity('custom', valid);
355 }
356 return ngModelValue;
357 }
358
359 ctrl.$parsers.push(customValidatorWrapper);
360 }
361 };
362 });
363})();