@syncfusion/ej2-angular-base 20.2.49 → 20.3.50
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +7 -27
- package/dist/ej2-angular-base.umd.min.js +2 -2
- package/dist/ej2-angular-base.umd.min.js.map +1 -1
- package/dist/es6/ej2-angular-base.es2015.js +11 -11
- package/dist/es6/ej2-angular-base.es2015.js.map +1 -1
- package/dist/es6/ej2-angular-base.es5.js +12 -11
- package/dist/es6/ej2-angular-base.es5.js.map +1 -1
- package/dist/global/ej2-angular-base.min.js +2 -2
- package/dist/global/ej2-angular-base.min.js.map +1 -1
- package/dist/global/index.d.ts +1 -1
- package/dist/ts/complex-array-base.ts +262 -0
- package/dist/ts/component-base.ts +381 -0
- package/dist/ts/form-base.ts +156 -0
- package/dist/ts/template.ts +81 -0
- package/dist/ts/util.ts +143 -0
- package/package.json +17 -7
- package/schematics/utils/get-project.js +3 -0
- package/src/form-base.js +11 -10
- package/src/template.js +1 -1
|
@@ -0,0 +1,381 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Angular Component Base Module
|
|
3
|
+
*/
|
|
4
|
+
import { getValue, isUndefined, setValue, isNullOrUndefined, attributes, createElement } from '@syncfusion/ej2-base';
|
|
5
|
+
import { EventEmitter, EmbeddedViewRef, Renderer2, ElementRef } from '@angular/core';
|
|
6
|
+
import { clearTemplate, registerEvents } from './util';
|
|
7
|
+
|
|
8
|
+
const SVG_REG: RegExp = /^svg|^path|^g/;
|
|
9
|
+
|
|
10
|
+
export interface IComponentBase {
|
|
11
|
+
registerEvents: (eventList: string[]) => void;
|
|
12
|
+
addTwoWay: (propList: string[]) => void;
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
interface Tag {
|
|
16
|
+
hasChanges: boolean;
|
|
17
|
+
getProperties?: Function;
|
|
18
|
+
isInitChanges: boolean;
|
|
19
|
+
hasNewChildren: boolean;
|
|
20
|
+
list: TagList[];
|
|
21
|
+
clearTemplate?: (arg: string[]) => void;
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
interface TagList {
|
|
25
|
+
getProperties: Function;
|
|
26
|
+
hasChanges: boolean;
|
|
27
|
+
isUpdated: boolean;
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
export class ComponentBase<T> {
|
|
31
|
+
public element: HTMLElement;
|
|
32
|
+
public tags: string[];
|
|
33
|
+
private ngAttr: string;
|
|
34
|
+
private srenderer: Renderer2;
|
|
35
|
+
protected isProtectedOnChange: boolean = true;
|
|
36
|
+
private isAngular: boolean;
|
|
37
|
+
private isFormInit: boolean = true;
|
|
38
|
+
public preventChange: boolean;
|
|
39
|
+
public isPreventChange: boolean;
|
|
40
|
+
protected oldProperties: { [key: string]: Object };
|
|
41
|
+
protected changedProperties: { [key: string]: Object };
|
|
42
|
+
protected finalUpdate: Function;
|
|
43
|
+
protected isUpdated: boolean;
|
|
44
|
+
public ngEle: ElementRef;
|
|
45
|
+
|
|
46
|
+
private tagObjects: { name: string, instance: Tag }[];
|
|
47
|
+
public onPropertyChanged: (newProp: Object, oldProp: Object) => void;
|
|
48
|
+
public appendTo: (ele: string | HTMLElement) => void;
|
|
49
|
+
public setProperties: (obj: Object, muteOnChange: boolean) => void;
|
|
50
|
+
public properties: Object;
|
|
51
|
+
public dataBind: Function;
|
|
52
|
+
private createElement: Function;
|
|
53
|
+
protected saveChanges(key: string, newValue: Object, oldValue: Object): void {
|
|
54
|
+
if (this.isProtectedOnChange) { return; }
|
|
55
|
+
this.oldProperties[key] = oldValue;
|
|
56
|
+
this.changedProperties[key] = newValue;
|
|
57
|
+
this.finalUpdate();
|
|
58
|
+
// tslint:disable-next-line:no-any
|
|
59
|
+
let changeTime: any = setTimeout(this.dataBind.bind(this));
|
|
60
|
+
let clearUpdate: Function = () => {
|
|
61
|
+
clearTimeout(changeTime);
|
|
62
|
+
};
|
|
63
|
+
this.finalUpdate = clearUpdate;
|
|
64
|
+
};
|
|
65
|
+
|
|
66
|
+
public destroy: Function;
|
|
67
|
+
private registeredTemplate: { [key: string]: EmbeddedViewRef<Object>[] };
|
|
68
|
+
private complexTemplate: string[];
|
|
69
|
+
|
|
70
|
+
private ngBoundedEvents: { [key: string]: Map<object, object> };
|
|
71
|
+
// tslint:disable-next-line:no-any
|
|
72
|
+
public ngOnInit(isTempRef?: any): void {
|
|
73
|
+
// tslint:disable-next-line:no-any
|
|
74
|
+
let tempOnThis: any = isTempRef || this;
|
|
75
|
+
tempOnThis.registeredTemplate = {};
|
|
76
|
+
tempOnThis.ngBoundedEvents = {};
|
|
77
|
+
tempOnThis.isAngular = true;
|
|
78
|
+
tempOnThis.isFormInit = true;
|
|
79
|
+
/* istanbul ignore next */
|
|
80
|
+
if (isTempRef) {
|
|
81
|
+
this.tags = isTempRef.tags;
|
|
82
|
+
}
|
|
83
|
+
tempOnThis.tags = this.tags || [];
|
|
84
|
+
tempOnThis.complexTemplate = this.complexTemplate || [];
|
|
85
|
+
tempOnThis.tagObjects = [];
|
|
86
|
+
tempOnThis.ngAttr = this.getAngularAttr(tempOnThis.element);
|
|
87
|
+
/* istanbul ignore next */
|
|
88
|
+
tempOnThis.createElement = (tagName: string, prop?:
|
|
89
|
+
{ id?: string, className?: string, innerHTML?: string, styles?: string, attrs?: { [key: string]: string } }) => {
|
|
90
|
+
//tslint:disable-next-line
|
|
91
|
+
let ele: Element = tempOnThis.srenderer ? tempOnThis.srenderer.createElement(tagName) : createElement(tagName);
|
|
92
|
+
if (typeof (prop) === 'undefined') {
|
|
93
|
+
return <HTMLElement>ele;
|
|
94
|
+
}
|
|
95
|
+
ele.innerHTML = (prop.innerHTML ? prop.innerHTML : '');
|
|
96
|
+
|
|
97
|
+
if (prop.className !== undefined) {
|
|
98
|
+
ele.className = prop.className;
|
|
99
|
+
}
|
|
100
|
+
if (prop.id !== undefined) {
|
|
101
|
+
ele.id = prop.id;
|
|
102
|
+
}
|
|
103
|
+
if (prop.styles !== undefined) {
|
|
104
|
+
ele.setAttribute('style', prop.styles);
|
|
105
|
+
}
|
|
106
|
+
if (tempOnThis.ngAttr !== undefined) {
|
|
107
|
+
ele.setAttribute(tempOnThis.ngAttr, '');
|
|
108
|
+
}
|
|
109
|
+
if (prop.attrs !== undefined) {
|
|
110
|
+
attributes(ele, prop.attrs);
|
|
111
|
+
}
|
|
112
|
+
return <HTMLElement>ele;
|
|
113
|
+
};
|
|
114
|
+
for (let tag of tempOnThis.tags) {
|
|
115
|
+
let tagObject: { name: string, instance: Tag } = {
|
|
116
|
+
instance: getValue('child' + tag.substring(0, 1).toUpperCase() + tag.substring(1), tempOnThis),
|
|
117
|
+
name: tag
|
|
118
|
+
};
|
|
119
|
+
tempOnThis.tagObjects.push(tagObject);
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
let complexTemplates: string[] = Object.keys(tempOnThis);
|
|
123
|
+
for (let i = 0; i < complexTemplates.length; i++) {
|
|
124
|
+
var compProp = getValue(complexTemplates[i], tempOnThis);
|
|
125
|
+
if (typeof compProp === 'object' && compProp && compProp.elementRef) {
|
|
126
|
+
if (typeof compProp === 'object' && compProp && compProp.elementRef && complexTemplates[i].indexOf('_') !== -1 && complexTemplates[i].indexOf('Ref') === -1) {
|
|
127
|
+
setValue(complexTemplates[i] + 'Ref', compProp, tempOnThis);
|
|
128
|
+
}
|
|
129
|
+
if (tempOnThis.viewContainerRef && !getValue("_viewContainerRef", compProp.elementRef.nativeElement) && !getValue("propName", compProp.elementRef.nativeElement)) {
|
|
130
|
+
setValue("_viewContainerRef", tempOnThis.viewContainerRef, compProp.elementRef.nativeElement);
|
|
131
|
+
setValue("propName", complexTemplates[i].replace("Ref", ''), compProp.elementRef.nativeElement);
|
|
132
|
+
}
|
|
133
|
+
}
|
|
134
|
+
}
|
|
135
|
+
complexTemplates = Object.keys(tempOnThis);
|
|
136
|
+
complexTemplates = complexTemplates.filter((val: string): boolean => {
|
|
137
|
+
return /Ref$/i.test(val) && /\_/i.test(val);
|
|
138
|
+
});
|
|
139
|
+
for (let tempName of complexTemplates) {
|
|
140
|
+
let propName: string = tempName.replace('Ref', '');
|
|
141
|
+
let val: Object = {};
|
|
142
|
+
setValue(propName.replace('_', '.'), getValue(propName, tempOnThis), val);
|
|
143
|
+
tempOnThis.setProperties(val, true);
|
|
144
|
+
}
|
|
145
|
+
}
|
|
146
|
+
|
|
147
|
+
public getAngularAttr(ele: Element): string {
|
|
148
|
+
let attributes: NamedNodeMap = ele.attributes;
|
|
149
|
+
let length: number = attributes.length;
|
|
150
|
+
let ngAr: string;
|
|
151
|
+
for (let i: number = 0; i < length; i++) {
|
|
152
|
+
/* istanbul ignore next */
|
|
153
|
+
if (/_ngcontent/g.test(attributes[i].name)) {
|
|
154
|
+
ngAr = attributes[i].name;
|
|
155
|
+
}
|
|
156
|
+
}
|
|
157
|
+
return ngAr;
|
|
158
|
+
};
|
|
159
|
+
// tslint:disable-next-line:no-any
|
|
160
|
+
public ngAfterViewInit(isTempRef?: any): void {
|
|
161
|
+
// tslint:disable-next-line:no-any
|
|
162
|
+
let tempAfterViewThis: any = isTempRef || this;
|
|
163
|
+
let regExp: RegExp = /ejs-tab|ejs-accordion/g;
|
|
164
|
+
/* istanbul ignore next */
|
|
165
|
+
if (regExp.test(tempAfterViewThis.ngEle.nativeElement.outerHTML)) {
|
|
166
|
+
tempAfterViewThis.ngEle.nativeElement.style.visibility = 'hidden';
|
|
167
|
+
}
|
|
168
|
+
|
|
169
|
+
/**
|
|
170
|
+
* Root level template properties are not getting rendered,
|
|
171
|
+
* Due to ngonchanges not get triggered.
|
|
172
|
+
* so that we have set template value for root level template properties,
|
|
173
|
+
* for example: refer below syntax
|
|
174
|
+
* ```html
|
|
175
|
+
* <ejs-grid>
|
|
176
|
+
* <e-column></e-column>
|
|
177
|
+
* <ng-template #editSettingsTemplate></ng-template>
|
|
178
|
+
* </ejs-grid>
|
|
179
|
+
* ```
|
|
180
|
+
*/
|
|
181
|
+
let templateProperties: string[] = Object.keys(tempAfterViewThis);
|
|
182
|
+
templateProperties = templateProperties.filter((val: string): boolean => {
|
|
183
|
+
return /Ref$/i.test(val);
|
|
184
|
+
});
|
|
185
|
+
for (let tempName of templateProperties) {
|
|
186
|
+
let propName: string = tempName.replace('Ref', '');
|
|
187
|
+
setValue(propName.replace('_', '.'), getValue(propName + 'Ref', tempAfterViewThis), tempAfterViewThis);
|
|
188
|
+
}
|
|
189
|
+
// Used setTimeout for template binding
|
|
190
|
+
// Refer Link: https://github.com/angular/angular/issues/6005
|
|
191
|
+
setTimeout(() => {
|
|
192
|
+
/* istanbul ignore else */
|
|
193
|
+
if (typeof window !== 'undefined' && tempAfterViewThis.element || tempAfterViewThis.getModuleName().includes('btn')) {
|
|
194
|
+
tempAfterViewThis.appendTo(tempAfterViewThis.element);
|
|
195
|
+
tempAfterViewThis.ngEle.nativeElement.style.visibility = '';
|
|
196
|
+
}
|
|
197
|
+
});
|
|
198
|
+
}
|
|
199
|
+
// tslint:disable-next-line:no-any
|
|
200
|
+
public ngOnDestroy(isTempRef?: any): void {
|
|
201
|
+
// tslint:disable-next-line:no-any
|
|
202
|
+
let tempOnDestroyThis: any = isTempRef || this;
|
|
203
|
+
/* istanbul ignore else */
|
|
204
|
+
setTimeout(() => {
|
|
205
|
+
if (typeof window !== 'undefined' && (tempOnDestroyThis.element.classList.contains('e-control'))) {
|
|
206
|
+
tempOnDestroyThis.destroy();
|
|
207
|
+
tempOnDestroyThis.clearTemplate(null);
|
|
208
|
+
// removing bounded events and tagobjects from component after destroy
|
|
209
|
+
tempOnDestroyThis.ngBoundedEvents = {};
|
|
210
|
+
tempOnDestroyThis.tagObjects = {};
|
|
211
|
+
tempOnDestroyThis.ngEle = null;
|
|
212
|
+
}
|
|
213
|
+
});
|
|
214
|
+
}
|
|
215
|
+
//tslint:disable-next-line
|
|
216
|
+
public clearTemplate(templateNames?: string[], index?: any): void {
|
|
217
|
+
clearTemplate(this, templateNames, index);
|
|
218
|
+
};
|
|
219
|
+
// tslint:disable-next-line:no-any
|
|
220
|
+
public ngAfterContentChecked(isTempRef?: any): void {
|
|
221
|
+
|
|
222
|
+
// tslint:disable-next-line:no-any
|
|
223
|
+
let tempAfterContentThis: any = isTempRef || this;
|
|
224
|
+
for (let tagObject of tempAfterContentThis.tagObjects) {
|
|
225
|
+
if (!isUndefined(tagObject.instance) &&
|
|
226
|
+
(tagObject.instance.isInitChanges || tagObject.instance.hasChanges || tagObject.instance.hasNewChildren)) {
|
|
227
|
+
if (tagObject.instance.isInitChanges) {
|
|
228
|
+
let propObj: { [key: string]: Object } = {};
|
|
229
|
+
// For angular 9 compatibility
|
|
230
|
+
// Not able to get complex directive properties reference ni Onint hook
|
|
231
|
+
// So we have constructed property here and used
|
|
232
|
+
let complexDirProps;
|
|
233
|
+
let list = getValue('instance.list', tagObject);
|
|
234
|
+
if (list && list.length) {
|
|
235
|
+
complexDirProps = list[0].directivePropList;
|
|
236
|
+
}
|
|
237
|
+
let skip: any = true;
|
|
238
|
+
if ((tempAfterContentThis as any).getModuleName && (tempAfterContentThis as any).getModuleName() === 'gantt') {
|
|
239
|
+
skip = false
|
|
240
|
+
}
|
|
241
|
+
if (complexDirProps && skip && complexDirProps.indexOf(tagObject.instance.propertyName) === -1) {
|
|
242
|
+
let compDirPropList = Object.keys(tagObject.instance.list[0].propCollection);
|
|
243
|
+
for (let h = 0; h < tagObject.instance.list.length; h++) {
|
|
244
|
+
tagObject.instance.list[h].propCollection[tagObject.instance.propertyName] = [];
|
|
245
|
+
let obj: any = {};
|
|
246
|
+
for (let k = 0; k < compDirPropList.length; k++) {
|
|
247
|
+
let complexPropName = compDirPropList[k];
|
|
248
|
+
obj[complexPropName] = tagObject.instance.list[h].propCollection[complexPropName];
|
|
249
|
+
}
|
|
250
|
+
for (let i = 0; i < tagObject.instance.list[h].tags.length; i++) {
|
|
251
|
+
let tag = tagObject.instance.list[h].tags[i];
|
|
252
|
+
let childObj = getValue('child' + tag.substring(0, 1).toUpperCase() + tag.substring(1), tagObject.instance.list[h]);
|
|
253
|
+
if (childObj) {
|
|
254
|
+
let innerchildObj = tagObject.instance.list[h]['child' + tag.substring(0, 1).toUpperCase() + tag.substring(1)];
|
|
255
|
+
if (innerchildObj) {
|
|
256
|
+
for (let j = 0; j < innerchildObj.list.length; j++) {
|
|
257
|
+
let innerTag = innerchildObj.list[0].tags[0];
|
|
258
|
+
if (innerTag) {
|
|
259
|
+
let innerchildTag = getValue('child' + innerTag.substring(0, 1).toUpperCase() + innerTag.substring(1), innerchildObj.list[j]);
|
|
260
|
+
if (innerchildTag) {
|
|
261
|
+
innerchildObj.list[j].tagObjects.push({ instance: innerchildTag, name: innerTag });
|
|
262
|
+
}
|
|
263
|
+
}
|
|
264
|
+
}
|
|
265
|
+
}
|
|
266
|
+
tagObject.instance.list[h].tagObjects.push({ instance: childObj, name: tag });
|
|
267
|
+
}
|
|
268
|
+
}
|
|
269
|
+
tagObject.instance.list[h].propCollection[tagObject.instance.propertyName].push(obj);
|
|
270
|
+
}
|
|
271
|
+
}
|
|
272
|
+
// End angular 9 compatibility
|
|
273
|
+
propObj[tagObject.name] = tagObject.instance.getProperties();
|
|
274
|
+
tempAfterContentThis.setProperties(propObj, tagObject.instance.isInitChanges);
|
|
275
|
+
} else {
|
|
276
|
+
/* istanbul ignore next */
|
|
277
|
+
if ((tempAfterContentThis[tagObject.name].length !== tagObject.instance.list.length) || (/diagram|tab|DashboardLayout/.test(tempAfterContentThis.getModuleName()))) {
|
|
278
|
+
tempAfterContentThis[tagObject.name] = tagObject.instance.list;
|
|
279
|
+
}
|
|
280
|
+
for (let list of tagObject.instance.list) {
|
|
281
|
+
let curIndex: number = tagObject.instance.list.indexOf(list);
|
|
282
|
+
let curChild: any = getValue(tagObject.name, tempAfterContentThis)[curIndex];
|
|
283
|
+
let complexTemplates: string[] = Object.keys(curChild);
|
|
284
|
+
complexTemplates = complexTemplates.filter((val: string): boolean => {
|
|
285
|
+
return /Ref$/i.test(val);
|
|
286
|
+
});
|
|
287
|
+
if (curChild.properties && Object.keys(curChild.properties).length !== 0){
|
|
288
|
+
for (let complexPropName of complexTemplates) {
|
|
289
|
+
complexPropName = complexPropName.replace(/Ref/, '');
|
|
290
|
+
curChild.properties[complexPropName] = !curChild.properties[complexPropName] ?
|
|
291
|
+
curChild.propCollection[complexPropName] : curChild.properties[complexPropName];
|
|
292
|
+
}
|
|
293
|
+
}
|
|
294
|
+
if (!isUndefined(curChild) && !isUndefined(curChild.setProperties)) {
|
|
295
|
+
if (/diagram|DashboardLayout/.test(tempAfterContentThis.getModuleName())) {
|
|
296
|
+
curChild.setProperties(list.getProperties(), true);
|
|
297
|
+
} else {
|
|
298
|
+
curChild.setProperties(list.getProperties());
|
|
299
|
+
}
|
|
300
|
+
}
|
|
301
|
+
list.isUpdated = true;
|
|
302
|
+
}
|
|
303
|
+
}
|
|
304
|
+
}
|
|
305
|
+
}
|
|
306
|
+
}
|
|
307
|
+
|
|
308
|
+
protected registerEvents(eventList: string[]): void {
|
|
309
|
+
registerEvents(eventList, this);
|
|
310
|
+
}
|
|
311
|
+
|
|
312
|
+
protected twoWaySetter(newVal: Object, prop: string): void {
|
|
313
|
+
let oldVal: Object = getValue(prop, this.properties);
|
|
314
|
+
if (oldVal === newVal) {
|
|
315
|
+
return;
|
|
316
|
+
}
|
|
317
|
+
this.saveChanges(prop, newVal, oldVal);
|
|
318
|
+
setValue(prop, (isNullOrUndefined(newVal) ? null : newVal), this.properties);
|
|
319
|
+
getValue(prop + 'Change', this).emit(newVal);
|
|
320
|
+
}
|
|
321
|
+
|
|
322
|
+
protected addTwoWay(propList: string[]): void {
|
|
323
|
+
for (let prop of propList) {
|
|
324
|
+
getValue(prop, this);
|
|
325
|
+
Object.defineProperty(this, prop, {
|
|
326
|
+
get: () => {
|
|
327
|
+
return getValue(prop, this.properties);
|
|
328
|
+
},
|
|
329
|
+
set: (newVal: Object) => this.twoWaySetter(newVal, prop)
|
|
330
|
+
});
|
|
331
|
+
setValue(prop + 'Change', new EventEmitter(), this);
|
|
332
|
+
}
|
|
333
|
+
}
|
|
334
|
+
|
|
335
|
+
public addEventListener(eventName: string, handler: Function): void {
|
|
336
|
+
let eventObj: EventEmitter<Object> = getValue(eventName, this);
|
|
337
|
+
if (!isUndefined(eventObj)) {
|
|
338
|
+
if (!this.ngBoundedEvents[eventName]) {
|
|
339
|
+
this.ngBoundedEvents[eventName] = new Map();
|
|
340
|
+
}
|
|
341
|
+
this.ngBoundedEvents[eventName].set(handler, eventObj.subscribe(handler));
|
|
342
|
+
}
|
|
343
|
+
}
|
|
344
|
+
|
|
345
|
+
public removeEventListener(eventName: string, handler: Function): void {
|
|
346
|
+
let eventObj: EventEmitter<Object> = getValue(eventName, this);
|
|
347
|
+
if (!isUndefined(eventObj)) {
|
|
348
|
+
(<EventEmitter<object>>this.ngBoundedEvents[eventName].get(handler)).unsubscribe();
|
|
349
|
+
}
|
|
350
|
+
}
|
|
351
|
+
|
|
352
|
+
public trigger(eventName: string, eventArgs: Object, success?: Function): void {
|
|
353
|
+
|
|
354
|
+
let eventObj: { next: Function } = getValue(eventName, this);
|
|
355
|
+
|
|
356
|
+
let prevDetection: boolean = this.isProtectedOnChange;
|
|
357
|
+
this.isProtectedOnChange = false;
|
|
358
|
+
|
|
359
|
+
if (eventArgs) {
|
|
360
|
+
(<{ name: string }>eventArgs).name = eventName;
|
|
361
|
+
}
|
|
362
|
+
|
|
363
|
+
if (!isUndefined(eventObj)) {
|
|
364
|
+
eventObj.next(eventArgs);
|
|
365
|
+
}
|
|
366
|
+
let localEventObj: Function = getValue('local' + eventName.charAt(0).toUpperCase() + eventName.slice(1), this);
|
|
367
|
+
if (!isUndefined(localEventObj)) {
|
|
368
|
+
localEventObj.call(this, eventArgs);
|
|
369
|
+
}
|
|
370
|
+
|
|
371
|
+
this.isProtectedOnChange = prevDetection;
|
|
372
|
+
/* istanbul ignore else */
|
|
373
|
+
if (success) {
|
|
374
|
+
this.preventChange = this.isPreventChange;
|
|
375
|
+
success.call(this, eventArgs);
|
|
376
|
+
}
|
|
377
|
+
this.isPreventChange = false;
|
|
378
|
+
|
|
379
|
+
}
|
|
380
|
+
|
|
381
|
+
}
|
|
@@ -0,0 +1,156 @@
|
|
|
1
|
+
import { EventEmitter, ElementRef } from '@angular/core';
|
|
2
|
+
import { getValue, setValue, isNullOrUndefined, isObject } from '@syncfusion/ej2-base';
|
|
3
|
+
import { ControlValueAccessor } from '@angular/forms';
|
|
4
|
+
/**
|
|
5
|
+
* Angular Form Base Module
|
|
6
|
+
*/
|
|
7
|
+
export class FormBase<T> implements ControlValueAccessor {
|
|
8
|
+
public value: T;
|
|
9
|
+
public checked: boolean;
|
|
10
|
+
private skipFromEvent: boolean;
|
|
11
|
+
static readonly isFormBase = true;
|
|
12
|
+
|
|
13
|
+
public propagateChange(_: T): void { return; }
|
|
14
|
+
public propagateTouch(): void { return; }
|
|
15
|
+
public enabled: Object;
|
|
16
|
+
public disabled: Object;
|
|
17
|
+
public angularValue: T;
|
|
18
|
+
private isFormInit: Boolean;
|
|
19
|
+
public objCheck: Boolean;
|
|
20
|
+
public duplicateValue: string;
|
|
21
|
+
public duplicateAngularValue: string;
|
|
22
|
+
|
|
23
|
+
public element: HTMLElement;
|
|
24
|
+
public inputElement: HTMLInputElement;
|
|
25
|
+
private ngEle: ElementRef;
|
|
26
|
+
public appendTo: (ele: string | HTMLElement) => void;
|
|
27
|
+
|
|
28
|
+
public focus: EventEmitter<Object>;
|
|
29
|
+
public blur: EventEmitter<Object>;
|
|
30
|
+
public preventChange: boolean;
|
|
31
|
+
public isUpdated: boolean;
|
|
32
|
+
public oldValue: any;
|
|
33
|
+
|
|
34
|
+
public localChange(e: { value?: T, checked?: T }): void {
|
|
35
|
+
//tslint:disable-next-line
|
|
36
|
+
let value: T | any = (e.checked === undefined ? e.value : e.checked);
|
|
37
|
+
this.objCheck = isObject(value);
|
|
38
|
+
if (this.isUpdated === true) {
|
|
39
|
+
this.angularValue = this.oldValue;
|
|
40
|
+
}
|
|
41
|
+
if (this.objCheck === true) {
|
|
42
|
+
this.duplicateValue = JSON.stringify(value);
|
|
43
|
+
this.duplicateAngularValue = JSON.stringify(this.angularValue);
|
|
44
|
+
if (this.duplicateValue !== this.duplicateAngularValue && this.propagateChange !== undefined && value !== undefined) {
|
|
45
|
+
// Update angular from our control
|
|
46
|
+
this.propagateChange(value);
|
|
47
|
+
this.angularValue = value;
|
|
48
|
+
}
|
|
49
|
+
} else {
|
|
50
|
+
if (value !== this.angularValue && this.propagateChange !== undefined && value !== undefined) {
|
|
51
|
+
// While reset form using reset() method ng-dirty not get updated, so while value is empty just update angularValue only
|
|
52
|
+
if (value !== '' && value !== null) {
|
|
53
|
+
// Update angular from our control
|
|
54
|
+
this.propagateChange(value);
|
|
55
|
+
this.angularValue = value;
|
|
56
|
+
} else {
|
|
57
|
+
//tslint:disable-next-line
|
|
58
|
+
let optionalValue: any = value;
|
|
59
|
+
this.propagateChange(optionalValue);
|
|
60
|
+
this.angularValue = value;
|
|
61
|
+
}
|
|
62
|
+
}
|
|
63
|
+
}
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
public properties: Object;
|
|
67
|
+
public saveChanges: Function;
|
|
68
|
+
|
|
69
|
+
|
|
70
|
+
public registerOnChange(registerFunction: (_: T) => void): void {
|
|
71
|
+
this.propagateChange = registerFunction;
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
public registerOnTouched(registerFunction: () => void): void {
|
|
75
|
+
this.propagateTouch = registerFunction;
|
|
76
|
+
}
|
|
77
|
+
public twoWaySetter(newVal: Object, prop: string): void {
|
|
78
|
+
let oldVal: Object = this.oldValue || getValue(prop, this.properties);
|
|
79
|
+
let ele: HTMLElement = this.inputElement || this.element;
|
|
80
|
+
if (ele && oldVal === newVal && this.value === newVal &&
|
|
81
|
+
((<HTMLInputElement>ele).value === undefined || (<HTMLInputElement>ele).value === '')) {
|
|
82
|
+
return;
|
|
83
|
+
}
|
|
84
|
+
this.saveChanges(prop, newVal, oldVal);
|
|
85
|
+
setValue(prop, (isNullOrUndefined(newVal) ? null : newVal), this.properties);
|
|
86
|
+
getValue(prop + 'Change', this).emit(newVal);
|
|
87
|
+
}
|
|
88
|
+
// tslint:disable-next-line:no-any
|
|
89
|
+
public ngAfterViewInit(isTempRef?: any): void {
|
|
90
|
+
// tslint:disable-next-line:no-any
|
|
91
|
+
let tempFormAfterViewThis: any = isTempRef || this;
|
|
92
|
+
// Used setTimeout for template binding
|
|
93
|
+
// Refer Link: https://github.com/angular/angular/issues/6005
|
|
94
|
+
// Removed setTimeout, Because we have called markForCheck() method in Angular Template Compiler
|
|
95
|
+
setTimeout(() => {
|
|
96
|
+
/* istanbul ignore else */
|
|
97
|
+
if (typeof window !== 'undefined') {
|
|
98
|
+
tempFormAfterViewThis.appendTo(tempFormAfterViewThis.element);
|
|
99
|
+
let ele: HTMLElement = tempFormAfterViewThis.inputElement || tempFormAfterViewThis.element;
|
|
100
|
+
ele.addEventListener('focus', tempFormAfterViewThis.ngOnFocus.bind(tempFormAfterViewThis));
|
|
101
|
+
ele.addEventListener('blur', tempFormAfterViewThis.ngOnBlur.bind(tempFormAfterViewThis));
|
|
102
|
+
}
|
|
103
|
+
this.isFormInit = false;
|
|
104
|
+
});
|
|
105
|
+
}
|
|
106
|
+
public setDisabledState(disabled: boolean): void {
|
|
107
|
+
this.enabled = !disabled;
|
|
108
|
+
this.disabled = disabled;
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
public writeValue(value: T): void {
|
|
112
|
+
let regExp: RegExp = /ejs-radiobutton/g;
|
|
113
|
+
//update control value from angular
|
|
114
|
+
if (this.checked === undefined) {
|
|
115
|
+
this.value = value;
|
|
116
|
+
} else {
|
|
117
|
+
// To resolve boolean type formControl value is not working for radio button control.
|
|
118
|
+
/* istanbul ignore next */
|
|
119
|
+
if (this.ngEle) {
|
|
120
|
+
if (typeof value === 'boolean') {
|
|
121
|
+
if (regExp.test(this.ngEle.nativeElement.outerHTML)) {
|
|
122
|
+
this.checked = value === this.value;
|
|
123
|
+
} else {
|
|
124
|
+
this.checked = value;
|
|
125
|
+
}
|
|
126
|
+
} else {
|
|
127
|
+
this.checked = value === this.value;
|
|
128
|
+
}
|
|
129
|
+
}
|
|
130
|
+
}
|
|
131
|
+
this.angularValue = value;
|
|
132
|
+
this.isUpdated = true;
|
|
133
|
+
// When binding Html textbox value to syncfusion textbox, change event triggered dynamically.
|
|
134
|
+
// To prevent change event, trigger change in component side based on `preventChange` value
|
|
135
|
+
this.preventChange = this.isFormInit ? false : true;
|
|
136
|
+
if (value === null) {
|
|
137
|
+
return;
|
|
138
|
+
}
|
|
139
|
+
|
|
140
|
+
}
|
|
141
|
+
|
|
142
|
+
public ngOnFocus(e: Event): void {
|
|
143
|
+
/* istanbul ignore else */
|
|
144
|
+
if (this.skipFromEvent !== true) {
|
|
145
|
+
this.focus.emit(e);
|
|
146
|
+
}
|
|
147
|
+
}
|
|
148
|
+
|
|
149
|
+
public ngOnBlur(e: Event): void {
|
|
150
|
+
this.propagateTouch();
|
|
151
|
+
/* istanbul ignore else */
|
|
152
|
+
if (this.skipFromEvent !== true) {
|
|
153
|
+
this.blur.emit(e);
|
|
154
|
+
}
|
|
155
|
+
}
|
|
156
|
+
}
|
|
@@ -0,0 +1,81 @@
|
|
|
1
|
+
import { ViewContainerRef, EmbeddedViewRef, ElementRef, TemplateRef } from '@angular/core';
|
|
2
|
+
import { setTemplateEngine, getTemplateEngine } from '@syncfusion/ej2-base';
|
|
3
|
+
import { setValue, getValue } from '@syncfusion/ej2-base';
|
|
4
|
+
|
|
5
|
+
let stringCompiler: (template: string, helper?: object) => (data: Object | JSON) => string = getTemplateEngine();
|
|
6
|
+
|
|
7
|
+
/**
|
|
8
|
+
* Angular Template Compiler
|
|
9
|
+
*/
|
|
10
|
+
export function compile(templateEle: AngularElementType, helper?: Object):
|
|
11
|
+
//tslint:disable-next-line
|
|
12
|
+
(data: Object | JSON, component?: any, propName?: any) => Object {
|
|
13
|
+
if (typeof templateEle === 'string') {
|
|
14
|
+
return stringCompiler(templateEle, helper);
|
|
15
|
+
} else {
|
|
16
|
+
let contRef: ViewContainerRef = templateEle.elementRef.nativeElement._viewContainerRef;
|
|
17
|
+
let pName: string = templateEle.elementRef.nativeElement.propName;
|
|
18
|
+
//tslint:disable-next-line
|
|
19
|
+
return (data: Object, component?: any, propName?: any): Object => {
|
|
20
|
+
let context: Object = { $implicit: data };
|
|
21
|
+
/* istanbul ignore next */
|
|
22
|
+
let conRef: ViewContainerRef = contRef ? contRef : component.viewContainerRef;
|
|
23
|
+
let viewRef: EmbeddedViewRef<Object> = conRef.createEmbeddedView(templateEle as TemplateRef<Object>, context);
|
|
24
|
+
viewRef.detectChanges();
|
|
25
|
+
/* istanbul ignore next */
|
|
26
|
+
let viewCollection: { [key: string]: EmbeddedViewRef<Object>[] } = (component && component.registeredTemplate) ?
|
|
27
|
+
component.registeredTemplate : getValue('currentInstance.registeredTemplate', conRef);
|
|
28
|
+
propName = (propName && component.registeredTemplate) ? propName : pName;
|
|
29
|
+
if (typeof viewCollection[propName] === 'undefined') {
|
|
30
|
+
viewCollection[propName] = [];
|
|
31
|
+
}
|
|
32
|
+
viewCollection[propName].push(viewRef);
|
|
33
|
+
return viewRef.rootNodes;
|
|
34
|
+
};
|
|
35
|
+
}
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
/**
|
|
39
|
+
* Property decorator for angular.
|
|
40
|
+
*/
|
|
41
|
+
export function Template<T>(defaultValue?: Object): PropertyDecorator {
|
|
42
|
+
return (target: Object, key: string) => {
|
|
43
|
+
let propertyDescriptor: Object = {
|
|
44
|
+
set: setter(key),
|
|
45
|
+
get: getter(key, defaultValue),
|
|
46
|
+
enumerable: true,
|
|
47
|
+
configurable: true
|
|
48
|
+
};
|
|
49
|
+
Object.defineProperty(target, key, propertyDescriptor);
|
|
50
|
+
};
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
function setter(key: string): Function {
|
|
54
|
+
return function (val: AngularElementType): void {
|
|
55
|
+
if (val === undefined) { return; }
|
|
56
|
+
setValue(key + 'Ref', val, this);
|
|
57
|
+
if (typeof val !== 'string') {
|
|
58
|
+
val.elementRef.nativeElement._viewContainerRef = this.viewContainerRef;
|
|
59
|
+
val.elementRef.nativeElement.propName = key;
|
|
60
|
+
} else {
|
|
61
|
+
if (this.saveChanges) {
|
|
62
|
+
this.saveChanges(key, val, undefined);
|
|
63
|
+
this.dataBind();
|
|
64
|
+
}
|
|
65
|
+
}
|
|
66
|
+
};
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
function getter(key: string, defaultValue: Object): Function {
|
|
70
|
+
return function (): Object {
|
|
71
|
+
/* istanbul ignore next */
|
|
72
|
+
return getValue(key + 'Ref', this) || defaultValue;
|
|
73
|
+
};
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
export interface AngularElementType {
|
|
77
|
+
elementRef: ElementRef;
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
//tslint:disable-next-line
|
|
81
|
+
setTemplateEngine({ compile: (compile as any) });
|