Sync Integ to Master
[sdc.git] / catalog-ui / src / app / ng2 / components / ui / dynamic-element / dynamic-element.component.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 import * as _ from "lodash";
22 import { Component, Compiler, EventEmitter, ViewContainerRef, ViewChild, Input, Output, ElementRef, ComponentRef, ComponentFactoryResolver } from '@angular/core'
23 import {ValidationConfiguration} from "app/models";
24 import {IUiElementChangeEvent} from "../form-components/ui-element-base.component";
25 import {UiElementInputComponent} from "../form-components/input/ui-element-input.component";
26 import {UiElementPopoverInputComponent} from "../form-components/popover-input/ui-element-popover-input.component";
27 import {UiElementIntegerInputComponent} from "../form-components/integer-input/ui-element-integer-input.component";
28 import {UiElementDropDownComponent, DropdownValue} from "../form-components/dropdown/ui-element-dropdown.component";
29 import {PROPERTY_DATA} from "../../../../utils/constants";
30
31 enum DynamicElementComponentCreatorIdentifier {
32     STRING,
33     INTEGER,
34     FLOAT,
35     BOOLEAN,
36     SUBNETPOOLID,
37     DEFAULT
38 }
39
40 @Component({
41     selector: 'dynamic-element',
42     template: `<div #target></div>`,
43     styleUrls: ['./dynamic-element.component.less'],
44     entryComponents: [
45         UiElementInputComponent,
46         UiElementDropDownComponent,
47         UiElementPopoverInputComponent,
48         UiElementIntegerInputComponent
49     ]
50 })
51 export class DynamicElementComponent {
52
53     @ViewChild('target', { read: ViewContainerRef }) target: any;
54     @Input() type: any;
55     @Input() name: string;
56     @Input() readonly:boolean;
57     @Input() path:string;//optional param. used only for for subnetpoolid type
58
59     @Input() value: any;
60     @Output() valueChange: EventEmitter<any> = new EventEmitter<any>();
61     @Output('elementChanged') emitter: EventEmitter<IUiElementChangeEvent> = new EventEmitter<IUiElementChangeEvent>();
62
63     cmpRef: ComponentRef<any>;
64     private isViewInitialized: boolean = false;
65     private elementCreatorIdentifier: DynamicElementComponentCreatorIdentifier;
66     validation = ValidationConfiguration.validation;
67
68     constructor(
69         private componentFactoryResolver: ComponentFactoryResolver,
70         private compiler: Compiler,
71         private el: ElementRef) {
72     }
73
74     updateComponent() {
75         if (!this.isViewInitialized) {
76             return;
77         }
78
79         // Factory to create component based on type or other property attributes.
80         const prevElementCreatorIdentifier: DynamicElementComponentCreatorIdentifier = this.elementCreatorIdentifier;
81         switch(true) {
82             case this.path && this.path.toUpperCase().indexOf("SUBNETPOOLID") !== -1:
83                 this.elementCreatorIdentifier = DynamicElementComponentCreatorIdentifier.SUBNETPOOLID;
84                 break;
85             case this.type === 'integer':
86                 this.elementCreatorIdentifier = DynamicElementComponentCreatorIdentifier.INTEGER;
87                 break;
88             case this.type === 'float':
89                 this.elementCreatorIdentifier = DynamicElementComponentCreatorIdentifier.FLOAT;
90                 break;
91             case PROPERTY_DATA.SCALAR_TYPES.indexOf(this.type) > -1:
92             case this.type === 'string':
93                 this.elementCreatorIdentifier = DynamicElementComponentCreatorIdentifier.STRING;
94                 break;
95             case this.type === 'boolean':
96                 this.elementCreatorIdentifier = DynamicElementComponentCreatorIdentifier.BOOLEAN;
97                 break;
98             default:
99                 this.elementCreatorIdentifier = DynamicElementComponentCreatorIdentifier.DEFAULT;
100         }
101
102         // In case the dynamic element creator is changed, then destroy old and build new.
103         if (this.elementCreatorIdentifier !== prevElementCreatorIdentifier) {
104             if (this.cmpRef) {
105                 this.cmpRef.destroy();
106             }
107             this.createComponentByIdentifier();
108         }
109
110         // Update attributes in base element class
111         if (this.cmpRef) {
112             this.cmpRef.instance.name = this.name;
113             this.cmpRef.instance.type = this.type;
114             this.cmpRef.instance.value = this.value;
115             this.cmpRef.instance.readonly = this.readonly;
116         }
117     }
118
119     createComponentByIdentifier() {
120         switch(this.elementCreatorIdentifier) {
121             case DynamicElementComponentCreatorIdentifier.SUBNETPOOLID:
122                 if(this.name.toUpperCase().indexOf("SUBNETPOOLID") == -1){//if it's an item of subnetpoolid list get the parent name
123                     let pathArray = this.path.split("#");
124                     this.name = pathArray[pathArray.length - 2];
125                 }
126                 this.createComponent(UiElementPopoverInputComponent);
127                 break;
128
129             case DynamicElementComponentCreatorIdentifier.INTEGER:
130                 this.createComponent(UiElementIntegerInputComponent);
131                 this.cmpRef.instance.pattern = this.validation.validationPatterns.integer;
132                 break;
133
134             case DynamicElementComponentCreatorIdentifier.FLOAT:
135                 this.createComponent(UiElementIntegerInputComponent);
136                 this.cmpRef.instance.pattern = /^[-+]?[0-9]+(\.[0-9]+)?([eE][-+]?[0-9]+)?$/;
137                 break;
138
139             case DynamicElementComponentCreatorIdentifier.STRING:
140                 this.createComponent(UiElementInputComponent);
141                 break;
142
143             case DynamicElementComponentCreatorIdentifier.BOOLEAN:
144                 this.createComponent(UiElementDropDownComponent);
145
146                 // Build drop down values
147                 let tmp = [];
148                 tmp.push(new DropdownValue(true,'TRUE'));
149                 tmp.push(new DropdownValue(false,'FALSE'));
150                 this.cmpRef.instance.values = tmp;
151                 if(!_.isUndefined(this.value)){//contains the real value (and not a string)
152                     this.value = JSON.parse(this.value);
153                 }
154                 break;
155
156             case DynamicElementComponentCreatorIdentifier.DEFAULT:
157             default:
158                 this.createComponent(UiElementInputComponent);
159                 console.log("ERROR: No ui component to handle type: " + this.type);
160         }
161
162         // Subscribe to change event of of ui-element-basic and fire event to change the value
163         this.cmpRef.instance.baseEmitter.subscribe((event) => { this.emitter.emit(event); });
164         this.cmpRef.instance.valueChange.subscribe((event) => { this.valueChange.emit(event); });
165     }
166
167     createComponent(ComponentToCreate:any):void {
168         let factory = this.componentFactoryResolver.resolveComponentFactory(ComponentToCreate);
169         this.cmpRef = this.target.createComponent(factory);
170     }
171
172     ngOnChanges() {
173         this.updateComponent();
174     }
175
176     ngAfterContentInit() {
177         this.isViewInitialized = true;
178         this.updateComponent();
179     }
180
181     ngOnDestroy() {
182         if (this.cmpRef) {
183             this.cmpRef.destroy();
184         }
185     }
186
187 }