[SDC-29] rebase continue work to align source
[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
7
8 @Component({
9     selector: 'dynamic-property',
10     templateUrl: './dynamic-property.component.html',
11     styleUrls: ['./dynamic-property.component.less']
12 })
13 export class DynamicPropertyComponent {
14
15     derivedPropertyTypes = DerivedPropertyType; //http://stackoverflow.com/questions/35835984/how-to-use-a-typescript-enum-value-in-an-angular2-ngswitch-statement
16     propType: DerivedPropertyType;
17     propPath: string;
18     isPropertyFEModel: boolean;
19     childrenCount: number;
20
21     @Input() canBeDeclared: boolean;
22     @Input() property: PropertyFEModel | DerivedFEProperty;
23     @Input() expandedChildId: string;
24     @Input() selectedPropertyId: string;
25     @Input() propertyNameSearchText: string;
26     @Input() readonly: boolean;
27
28     @Output() valueChanged: EventEmitter<any> = new EventEmitter<any>();
29     @Output() expandChild: EventEmitter<string> = new EventEmitter<string>();
30     @Output() checkProperty: EventEmitter<string> = new EventEmitter<string>();
31     @Output() deleteItem: EventEmitter<string> = new EventEmitter<string>();
32     @Output() clickOnPropertyRow: EventEmitter<PropertyFEModel | DerivedFEProperty> = new EventEmitter<PropertyFEModel | DerivedFEProperty>();
33     @Output() mapKeyChanged: EventEmitter<string> = new EventEmitter<string>();
34     @Output() addChildPropsToParent: EventEmitter<Array<DerivedFEProperty>> = new EventEmitter<Array<DerivedFEProperty>>();
35
36
37     constructor(private propertiesUtils: PropertiesUtils, private dataTypeService: DataTypeService) {
38     }
39
40     ngOnInit() {
41         this.isPropertyFEModel = this.property instanceof PropertyFEModel;
42         this.propType = this.property.derivedDataType;
43         this.propPath = (this.property instanceof PropertyFEModel) ? this.property.name : this.property.propertiesName;
44     }
45
46
47     onClickPropertyRow = (property, event) => {
48         // Because DynamicPropertyComponent is recrusive second time the event is fire event.stopPropagation = undefined
49         event && event.stopPropagation && event.stopPropagation();
50         this.clickOnPropertyRow.emit(property);
51     }
52
53
54     expandChildById = (id: string) => {
55         this.expandedChildId = id;
56         this.expandChild.emit(id);
57     }
58
59     checkedChange = (propName: string) => {
60         this.checkProperty.emit(propName);
61     }
62
63     hasChildren = (): number => {
64         return (this.property.valueObj && typeof this.property.valueObj == 'object') ? Object.keys(this.property.valueObj).length : 0;
65     }
66
67     createNewChildProperty = (): void => {
68         
69         let newProps: Array<DerivedFEProperty> = this.propertiesUtils.createListOrMapChildren(this.property, "", null);
70         if (this.property instanceof PropertyFEModel) {
71             this.addChildProps(newProps, this.property.name);
72         } else {
73             this.addChildPropsToParent.emit(newProps);
74         }
75     }
76
77     addChildProps = (newProps: Array<DerivedFEProperty>, childPropName: string) => {
78         
79         if (this.property instanceof PropertyFEModel) {
80             let insertIndex: number = this.property.getIndexOfChild(childPropName) + this.property.getCountOfChildren(childPropName); //insert after parent prop and existing children 
81             this.property.flattenedChildren.splice(insertIndex, 0, ...newProps); //using ES6 spread operator 
82             this.expandChildById(newProps[0].propertiesName);
83         }
84     }
85
86     childValueChanged = (property: DerivedFEProperty) => { //value of child property changed
87
88         if (this.property instanceof PropertyFEModel) { // will always be the case
89             let parentNames = this.getParentNamesArray(property.propertiesName, []);
90             if (parentNames.length) {
91                 _.set(this.property.valueObj, parentNames.join('.'), property.valueObj);
92             }
93             console.log(parentNames);
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
131     getParentNamesArray = (parentPropName: string, parentNames?: Array<string>): Array<string> => {
132         if (this.property instanceof PropertyFEModel) {
133
134             if (parentPropName.indexOf("#") == -1) { return parentNames; } //finished recursing parents. return
135
136             let parentProp: DerivedFEProperty = this.property.flattenedChildren.find(prop => prop.propertiesName === parentPropName);
137             let nameToInsert: string = parentProp.name;
138
139             if (parentProp.isChildOfListOrMap) {
140                 if (parentProp.derivedDataType == DerivedPropertyType.MAP) {
141                     nameToInsert = parentProp.mapKey;
142                 } else { //LIST
143                     let siblingProps = this.property.flattenedChildren.filter(prop => prop.parentName == parentProp.parentName).map(prop => prop.propertiesName);
144                     nameToInsert = siblingProps.indexOf(parentProp.propertiesName).toString();
145                 }
146             }
147
148             parentNames.splice(0, 0, nameToInsert); //add prop name to array
149             return this.getParentNamesArray(parentProp.parentName, parentNames); //continue recursing
150             
151         }
152     }
153
154
155 }