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