[sdc] update code of sdc
[sdc.git] / catalog-ui / src / app / ng2 / components / properties-table / dynamic-property / dynamic-property.component.ts
1 import {Component, Input, Output, EventEmitter} from "@angular/core";
2 import { PropertyBEModel, PropertyFEModel, DerivedFEProperty, DerivedPropertyType, SchemaPropertyGroupModel, DataTypeModel } from "app/models";
3 import { PROPERTY_DATA, PROPERTY_TYPES } from 'app/utils';
4 import { PropertiesUtils } from "app/ng2/pages/properties-assignment/properties.utils";
5 import { DataTypeService } from "../../../services/data-type.service";
6 import { trigger, state, style, transition, animate } from '@angular/core';
7
8
9 @Component({
10     selector: 'dynamic-property',
11     templateUrl: './dynamic-property.component.html',
12     styleUrls: ['./dynamic-property.component.less'],
13     animations: [trigger('fadeIn', [transition(':enter', [style({ opacity: '0' }), animate('.7s ease-out', style({ opacity: '1' }))])])]
14 })
15 export class DynamicPropertyComponent {
16
17     derivedPropertyTypes = DerivedPropertyType; //http://stackoverflow.com/questions/35835984/how-to-use-a-typescript-enum-value-in-an-angular2-ngswitch-statement
18     propType: DerivedPropertyType;
19     propPath: string;
20     isPropertyFEModel: boolean;
21     nestedLevel: number;
22
23     @Input() canBeDeclared: boolean;
24     @Input() property: PropertyFEModel | DerivedFEProperty;
25     @Input() expandedChildId: string;
26     @Input() selectedPropertyId: string;
27     @Input() propertyNameSearchText: string;
28     @Input() readonly: boolean;
29
30     @Output() valueChanged: EventEmitter<any> = new EventEmitter<any>();
31     @Output() expandChild: EventEmitter<string> = new EventEmitter<string>();
32     @Output() checkProperty: EventEmitter<string> = new EventEmitter<string>();
33     @Output() deleteItem: EventEmitter<string> = new EventEmitter<string>();
34     @Output() clickOnPropertyRow: EventEmitter<PropertyFEModel | DerivedFEProperty> = new EventEmitter<PropertyFEModel | DerivedFEProperty>();
35     @Output() mapKeyChanged: EventEmitter<string> = new EventEmitter<string>();
36     @Output() addChildPropsToParent: EventEmitter<Array<DerivedFEProperty>> = new EventEmitter<Array<DerivedFEProperty>>();
37
38
39     constructor(private propertiesUtils: PropertiesUtils, private dataTypeService: DataTypeService) {
40     }
41
42     ngOnInit() {
43         this.isPropertyFEModel = this.property instanceof PropertyFEModel;
44         this.propType = this.property.derivedDataType;
45         this.propPath = (this.property instanceof PropertyFEModel) ? this.property.name : this.property.propertiesName;
46         this.nestedLevel = (this.property.propertiesName.match(/#/g) || []).length;
47     }
48
49
50     onClickPropertyRow = (property, event) => {
51         // Because DynamicPropertyComponent is recrusive second time the event is fire event.stopPropagation = undefined
52         event && event.stopPropagation && event.stopPropagation();
53         this.clickOnPropertyRow.emit(property);
54     }
55
56
57     expandChildById = (id: string) => {
58         this.expandedChildId = id;
59         this.expandChild.emit(id);
60     }
61
62     checkedChange = (propName: string) => {
63         this.checkProperty.emit(propName);
64     }
65
66     hasChildren = (): number => {
67         return (this.property.valueObj && typeof this.property.valueObj == 'object') ? Object.keys(this.property.valueObj).length : 0;
68     }
69
70     createNewChildProperty = (): void => {
71         
72         let newProps: Array<DerivedFEProperty> = this.propertiesUtils.createListOrMapChildren(this.property, "", undefined);
73         if (this.property instanceof PropertyFEModel) {
74             this.addChildProps(newProps, this.property.name);
75         } else {
76             this.addChildPropsToParent.emit(newProps);
77         }
78     }
79
80     addChildProps = (newProps: Array<DerivedFEProperty>, childPropName: string) => {
81         
82         if (this.property instanceof PropertyFEModel) {
83             let insertIndex: number = this.property.getIndexOfChild(childPropName) + this.property.getCountOfChildren(childPropName); //insert after parent prop and existing children 
84             this.property.flattenedChildren.splice(insertIndex, 0, ...newProps); //using ES6 spread operator 
85             this.expandChildById(newProps[0].propertiesName);
86         }
87     }
88
89     childValueChanged = (property: DerivedFEProperty) => { //value of child property changed
90
91         if (this.property instanceof PropertyFEModel) { // will always be the case
92             this.property.childPropUpdated(property);
93             this.dataTypeService.checkForCustomBehavior(this.property);
94             this.valueChanged.emit(this.property.name);
95         }
96     }    
97
98     deleteListOrMapItem = (item: DerivedFEProperty) => {
99         if (this.property instanceof PropertyFEModel) {
100             this.removeValueFromParent(item);
101             this.property.flattenedChildren.splice(this.property.getIndexOfChild(item.propertiesName), this.property.getCountOfChildren(item.propertiesName));
102             this.expandChildById(item.propertiesName);
103         }
104     }
105
106     removeValueFromParent = (item: DerivedFEProperty, replaceKey?: string) => {
107         if (this.property instanceof PropertyFEModel) {
108             let itemParent = (item.parentName == this.property.name) ? this.property : this.property.flattenedChildren.find(prop => prop.propertiesName == item.parentName);
109
110             if (item.derivedDataType == DerivedPropertyType.MAP) {
111                 let oldKey = item.mapKey;
112                 if (typeof replaceKey == 'string') { //allow saving empty string
113                     _.set(itemParent.valueObj, replaceKey, itemParent.valueObj[oldKey]);
114                     item.mapKey = replaceKey;
115                 }
116                 delete itemParent.valueObj[oldKey];
117             } else {
118                 let itemIndex: number = this.property.flattenedChildren.filter(prop => prop.parentName == item.parentName).map(prop => prop.propertiesName).indexOf(item.propertiesName);
119                 itemParent.valueObj.splice(itemIndex, 1);
120             }
121
122             if (itemParent instanceof PropertyFEModel) { //direct child
123                 this.valueChanged.emit(this.property.name);
124             } else { //nested child - need to update parent prop by getting flattened name (recurse through parents and replace map/list keys, etc)
125                 this.childValueChanged(itemParent);
126             }
127         }
128     }
129
130 }