Fix handling of default values for VFC properties
[sdc.git] / catalog-ui / src / app / directives / property-types / data-type-fields-structure / data-type-fields-structure.ts
1 /*-
2  * ============LICENSE_START=======================================================
3  * SDC
4  * ================================================================================
5  * Copyright (C) 2017 AT&T Intellectual Property. All rights reserved.
6  * ================================================================================
7  * Licensed under the Apache License, Version 2.0 (the "License");
8  * you may not use this file except in compliance with the License.
9  * You may obtain a copy of the License at
10  *
11  *      http://www.apache.org/licenses/LICENSE-2.0
12  *
13  * Unless required by applicable law or agreed to in writing, software
14  * distributed under the License is distributed on an "AS IS" BASIS,
15  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
16  * See the License for the specific language governing permissions and
17  * limitations under the License.
18  * ============LICENSE_END=========================================================
19  */
20
21 /**
22  * Created by obarda on 1/27/2016.
23  */
24 'use strict';
25 import { DataTypesMap } from 'app/models';
26 import { DataTypePropertyModel } from 'app/models/data-type-properties';
27 import { DataTypesService } from 'app/services';
28 import { ValidationUtils } from 'app/utils';
29 import * as _ from 'lodash';
30
31 export interface IDataTypeFieldsStructureScope extends ng.IScope {
32     parentFormObj: ng.IFormController;
33     dataTypeProperties: DataTypePropertyModel[];
34     typeName: string;
35     valueObjRef: any;
36     propertyNameValidationPattern: RegExp;
37     fieldsPrefixName: string;
38     readOnly: boolean;
39     currentTypeDefaultValue: any;
40     types: DataTypesMap;
41     expandByDefault: boolean;
42     expand: boolean;
43     expanded: boolean;
44     dataTypesService: DataTypesService;
45     constraints: string[];
46
47     expandAndCollapse(): void;
48     getValidationPattern(type: string): RegExp;
49     validateIntRange(value: string): boolean;
50     onValueChange(propertyName: string, type: string): void;
51     inputOnValueChange(property: any): void;
52 }
53
54 export class DataTypeFieldsStructureDirective implements ng.IDirective {
55
56     constraints: string[];
57
58     scope = {
59         valueObjRef: '=',
60         typeName: '=',
61         parentFormObj: '=',
62         fieldsPrefixName: '=',
63         readOnly: '=',
64         defaultValue: '@',
65         types: '=',
66         expandByDefault: '='
67     };
68
69     restrict = 'E';
70     replace = true;
71
72     constructor(private DataTypesService: DataTypesService,
73                 private PropertyNameValidationPattern: RegExp,
74                 private ValidationUtils: ValidationUtils) {
75     }
76
77     public static factory = (DataTypesService: DataTypesService,
78                              PropertyNameValidationPattern: RegExp,
79                              ValidationUtils: ValidationUtils) => {
80         return new DataTypeFieldsStructureDirective(DataTypesService, PropertyNameValidationPattern, ValidationUtils);
81     }
82     template = (): string => {
83         return require('./data-type-fields-structure.html');
84     }
85
86     link = (scope: IDataTypeFieldsStructureScope, element: any, $attr: any) => {
87         scope.propertyNameValidationPattern = this.PropertyNameValidationPattern;
88
89         scope.$watchCollection('[typeName,fieldsPrefixName]', (newData: any): void => {
90             this.rerender(scope);
91         });
92
93         scope.expandAndCollapse = (): void => {
94             if (!scope.expanded) {
95                 this.initDataOnScope(scope, $attr);
96                 scope.expanded = true;
97             }
98             scope.expand = !scope.expand;
99         };
100
101         scope.getValidationPattern = (type: string): RegExp => {
102             return this.ValidationUtils.getValidationPattern(type);
103         };
104
105         scope.validateIntRange = (value: string): boolean => {
106             return !value || this.ValidationUtils.validateIntRange(value);
107         };
108
109         scope.onValueChange = (propertyName: string, type: string, ): void => {
110             scope.valueObjRef[propertyName] = !angular.isUndefined(scope.valueObjRef[propertyName]) ? scope.valueObjRef[propertyName] : scope.currentTypeDefaultValue[propertyName];
111             if (scope.valueObjRef[propertyName] && type != 'string') {
112                 scope.valueObjRef[propertyName] = JSON.parse(scope.valueObjRef[propertyName]);
113             }
114         };
115
116         scope.inputOnValueChange = (property: any) => {
117             if (property.constraints) {
118                 // this.constraints = property.constraints[0].validValues;
119             }
120
121             const value = !scope.parentFormObj[scope.fieldsPrefixName + property.name].$error.pattern
122                 && ('integer' == property.type && scope.parentFormObj[scope.fieldsPrefixName + property.name].$setValidity('pattern', scope.validateIntRange(scope.valueObjRef[property.name]))
123                 || scope.onValueChange(property.name, (property.simpleType || property.type)));
124             return value;
125         };
126     }
127     // public types=Utils.Constants.PROPERTY_DATA.TYPES;
128
129     // get data type properties array and return object with the properties and their default value
130     // (for example: get: [{name:"prop1",defaultValue:1 ...},{name:"prop2", defaultValue:"bla bla" ...}]
131     //              return: {prop1: 1, prop2: "bla bla"}
132     private getDefaultValue = (dataTypeProperties: DataTypePropertyModel[]): any => {
133         const defaultValue = {};
134         for (const element of dataTypeProperties) {
135             if (element.type != 'string') {
136                 if (!angular.isUndefined(element.defaultValue)) {
137                     defaultValue[element.name] = JSON.parse(element.defaultValue);
138                 }
139             } else {
140                 defaultValue[element.name] = element.defaultValue;
141             }
142         }
143         return defaultValue;
144     }
145
146     private initDataOnScope = (scope: any, $attr: any): void => {
147         scope.dataTypesService = this.DataTypesService;
148         scope.dataTypeProperties = this.getDataTypeProperties(scope.typeName, scope.types);
149         if ($attr.defaultValue) {
150             scope.currentTypeDefaultValue = JSON.parse($attr.defaultValue);
151         } else {
152             scope.currentTypeDefaultValue = this.getDefaultValue(scope.dataTypeProperties);
153         }
154
155         if (!scope.valueObjRef) {
156             scope.valueObjRef = {};
157         }
158
159         _.forEach(scope.currentTypeDefaultValue, (value, key) => {
160             if (angular.isUndefined(scope.valueObjRef[key])) {
161                 if (typeof scope.currentTypeDefaultValue[key] == 'object') {
162                     angular.copy(scope.currentTypeDefaultValue[key], scope.valueObjRef[key]);
163                 } else {
164                     scope.valueObjRef[key] = scope.currentTypeDefaultValue[key];
165                 }
166             }
167         });
168     }
169
170     private getDataTypeProperties = (dataTypeName: string, typesInModel: DataTypesMap): DataTypePropertyModel[] => {
171         let properties = typesInModel[dataTypeName].properties || [];
172         if (typesInModel[dataTypeName].derivedFromName != 'tosca.datatypes.Root') {
173             properties = this.getDataTypeProperties(typesInModel[dataTypeName].derivedFromName, typesInModel).concat(properties);
174         }
175         return properties;
176     }
177
178     private rerender = (scope: any): void => {
179         scope.expanded = false;
180         scope.expand = false;
181         if (scope.expandByDefault) {
182             scope.expandAndCollapse();
183         }
184     }
185 }
186
187 DataTypeFieldsStructureDirective.factory.$inject = ['Sdc.Services.DataTypesService', 'PropertyNameValidationPattern', 'ValidationUtils'];