libs/core/form-tracking/src/lib/form-tracking.ts
Properties |
|
talyTrackingApplied (Optional) | |
Type |
boolean
|
import {
TalyAbstractControl,
getNativeElement$
} from '@allianz/taly-acl/input-element-injector-directive';
import { AbstractControl, isFormArray, isFormControl, isFormGroup } from '@angular/forms';
import { Observable, debounceTime, filter, fromEvent, merge, switchMap, takeUntil } from 'rxjs';
export interface TalyAbstractTrackingControl extends AbstractControl {
talyTrackingApplied?: boolean;
}
export type PushEventFunction = (id: string, value: unknown) => void;
export function trackForm(
controlOrGroup: AbstractControl,
trackingIdPrefix: string,
untilDestroyed$: Observable<unknown>,
pushEvent: PushEventFunction
): void {
setupFormTracking(controlOrGroup, trackingIdPrefix, untilDestroyed$, pushEvent);
if (isFormControl(controlOrGroup)) {
return;
}
// Subscribe to detect new form controls being added or removed
controlOrGroup.statusChanges.pipe(takeUntil(untilDestroyed$), debounceTime(300)).subscribe(() => {
setupFormTracking(controlOrGroup, trackingIdPrefix, untilDestroyed$, pushEvent);
});
}
function setupFormTracking(
controlOrGroup: AbstractControl,
trackingIdPrefix: string,
untilDestroyed$: Observable<unknown>,
pushEvent: PushEventFunction,
parentPath: string[] = []
): void {
if (isFormControl(controlOrGroup)) {
if (!(controlOrGroup as TalyAbstractTrackingControl).talyTrackingApplied) {
trackControl(
controlOrGroup,
trackingIdPrefix,
parentPath.join('/'),
untilDestroyed$,
pushEvent
);
(controlOrGroup as TalyAbstractTrackingControl).talyTrackingApplied = true;
}
} else if (isFormGroup(controlOrGroup) || isFormArray(controlOrGroup)) {
const entries = Object.entries(controlOrGroup.controls);
for (const [path, nestedControl] of entries) {
const currentPath = [...parentPath, path];
setupFormTracking(nestedControl, trackingIdPrefix, untilDestroyed$, pushEvent, currentPath);
}
}
}
function trackControl(
control: AbstractControl,
trackingIdPrefix: string,
controlName: string,
untilDestroyed$: Observable<unknown>,
pushEvent: PushEventFunction
): void {
const getVisibleNativeElement$ = getNativeElement$(control).pipe(filter(Boolean));
control.statusChanges
?.pipe(takeUntil(merge(getVisibleNativeElement$, untilDestroyed$)), debounceTime(300))
.subscribe(() => {
pushTrackingEvents(control, trackingIdPrefix, controlName, pushEvent);
});
getVisibleNativeElement$
.pipe(
switchMap((nativeFormElement) => fromEvent(nativeFormElement, 'blur')),
takeUntil(untilDestroyed$)
)
.subscribe(() => {
pushTrackingEvents(control, trackingIdPrefix, controlName, pushEvent);
});
}
function pushTrackingEvents(
control: TalyAbstractControl,
trackingIdPrefix: string,
controlName: string,
pushEvent: (id: string, value: unknown) => void
): void {
const baseEventName = `automaticTALYTracking.${trackingIdPrefix}.${controlName}`;
pushEvent(`${baseEventName}.value`, getTrackingValue(control));
pushEvent(`${baseEventName}.valid`, control.valid);
pushEvent(`${baseEventName}.dirty`, control.dirty);
pushEvent(`${baseEventName}.touched`, control.touched);
pushEvent(`${baseEventName}.errors`, control.errors);
}
function getTrackingValue(control: TalyAbstractControl): unknown {
const nativeElement = getNativeElement$(control).value;
const trackingValue =
(nativeElement as HTMLInputElement)?.type === 'password' ? 'PROTECTED' : control.value;
return trackingValue;
}