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';
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' }))])])]
15 export class DynamicPropertyComponent {
17 derivedPropertyTypes = DerivedPropertyType; //http://stackoverflow.com/questions/35835984/how-to-use-a-typescript-enum-value-in-an-angular2-ngswitch-statement
18 propType: DerivedPropertyType;
20 isPropertyFEModel: boolean;
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;
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>>();
39 constructor(private propertiesUtils: PropertiesUtils, private dataTypeService: DataTypeService) {
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;
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);
57 expandChildById = (id: string) => {
58 this.expandedChildId = id;
59 this.expandChild.emit(id);
62 checkedChange = (propName: string) => {
63 this.checkProperty.emit(propName);
66 hasChildren = (): number => {
67 return (this.property.valueObj && typeof this.property.valueObj == 'object') ? Object.keys(this.property.valueObj).length : 0;
70 createNewChildProperty = (): void => {
72 let newProps: Array<DerivedFEProperty> = this.propertiesUtils.createListOrMapChildren(this.property, "", undefined);
73 if (this.property instanceof PropertyFEModel) {
74 this.addChildProps(newProps, this.property.name);
76 this.addChildPropsToParent.emit(newProps);
80 addChildProps = (newProps: Array<DerivedFEProperty>, childPropName: string) => {
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);
89 childValueChanged = (property: DerivedFEProperty) => { //value of child property changed
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);
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);