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";
9 selector: 'dynamic-property',
10 templateUrl: './dynamic-property.component.html',
11 styleUrls: ['./dynamic-property.component.less']
13 export class DynamicPropertyComponent {
15 derivedPropertyTypes = DerivedPropertyType; //http://stackoverflow.com/questions/35835984/how-to-use-a-typescript-enum-value-in-an-angular2-ngswitch-statement
16 propType: DerivedPropertyType;
18 isPropertyFEModel: boolean;
19 childrenCount: number;
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;
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>>();
37 constructor(private propertiesUtils: PropertiesUtils, private dataTypeService: DataTypeService) {
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;
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);
54 expandChildById = (id: string) => {
55 this.expandedChildId = id;
56 this.expandChild.emit(id);
59 checkedChange = (propName: string) => {
60 this.checkProperty.emit(propName);
63 hasChildren = (): number => {
64 return (this.property.valueObj && typeof this.property.valueObj == 'object') ? Object.keys(this.property.valueObj).length : 0;
67 createNewChildProperty = (): void => {
69 let newProps: Array<DerivedFEProperty> = this.propertiesUtils.createListOrMapChildren(this.property, "", null);
70 if (this.property instanceof PropertyFEModel) {
71 this.addChildProps(newProps, this.property.name);
73 this.addChildPropsToParent.emit(newProps);
77 addChildProps = (newProps: Array<DerivedFEProperty>, childPropName: string) => {
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);
86 childValueChanged = (property: DerivedFEProperty) => { //value of child property changed
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);
93 console.log(parentNames);
94 this.valueChanged.emit(this.property.name);
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);
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);
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;
116 delete itemParent.valueObj[oldKey];
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);
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);
131 getParentNamesArray = (parentPropName: string, parentNames?: Array<string>): Array<string> => {
132 if (this.property instanceof PropertyFEModel) {
134 if (parentPropName.indexOf("#") == -1) { return parentNames; } //finished recursing parents. return
136 let parentProp: DerivedFEProperty = this.property.flattenedChildren.find(prop => prop.propertiesName === parentPropName);
137 let nameToInsert: string = parentProp.name;
139 if (parentProp.isChildOfListOrMap) {
140 if (parentProp.derivedDataType == DerivedPropertyType.MAP) {
141 nameToInsert = parentProp.mapKey;
143 let siblingProps = this.property.flattenedChildren.filter(prop => prop.parentName == parentProp.parentName).map(prop => prop.propertiesName);
144 nameToInsert = siblingProps.indexOf(parentProp.propertiesName).toString();
148 parentNames.splice(0, 0, nameToInsert); //add prop name to array
149 return this.getParentNamesArray(parentProp.parentName, parentNames); //continue recursing