mirror of
https://github.com/Alfresco/alfresco-ng2-components.git
synced 2025-07-24 17:32:15 +00:00
[AAE-8086] Propagate form events (#7572)
* [AAE-8086] Propagate events * [AAE-8086] Add form rules manager to the form renderer * [AAE-8086] Extensibility improvements * [AAE-8086] Fix wrong import * [AAE-8087] Add form actions * [AAE-8086] Initialize form rules manager on form renderer component changes * [AAE-8087] Fix form actions * [AAE-8087] Fix unit tests for field visibility * trigger travis
This commit is contained in:
committed by
GitHub
parent
48c3fac018
commit
a02a8a4ad9
@@ -113,7 +113,8 @@ describe('FormFieldComponent', () => {
|
||||
component.field.isVisible = false;
|
||||
fixture.detectChanges();
|
||||
fixture.whenStable().then(() => {
|
||||
expect(fixture.nativeElement.querySelector('#field-FAKE-TXT-WIDGET-container').hidden).toBeTruthy();
|
||||
const debugElement = fixture.nativeElement.querySelector('#field-FAKE-TXT-WIDGET-container').style.visibility;
|
||||
expect(debugElement).toEqual('hidden');
|
||||
done();
|
||||
});
|
||||
});
|
||||
@@ -128,7 +129,7 @@ describe('FormFieldComponent', () => {
|
||||
fixture.detectChanges();
|
||||
|
||||
fixture.whenStable().then(() => {
|
||||
expect(fixture.nativeElement.querySelector('#field-FAKE-TXT-WIDGET-container').hidden).toBeFalsy();
|
||||
expect(fixture.nativeElement.querySelector('#field-FAKE-TXT-WIDGET-container').style.visibility).toEqual('visible');
|
||||
done();
|
||||
});
|
||||
});
|
||||
@@ -141,10 +142,10 @@ describe('FormFieldComponent', () => {
|
||||
|
||||
component.field = field;
|
||||
fixture.detectChanges();
|
||||
expect(fixture.nativeElement.querySelector('#field-FAKE-TXT-WIDGET-container').hidden).toBeFalsy();
|
||||
expect(fixture.nativeElement.querySelector('#field-FAKE-TXT-WIDGET-container').style.visibility).toEqual('visible');
|
||||
component.field.isVisible = false;
|
||||
fixture.detectChanges();
|
||||
expect(fixture.nativeElement.querySelector('#field-FAKE-TXT-WIDGET-container').hidden).toBeTruthy();
|
||||
expect(fixture.nativeElement.querySelector('#field-FAKE-TXT-WIDGET-container').style.visibility).toEqual('hidden');
|
||||
});
|
||||
|
||||
it('[C213878] - Should fields be correctly rendered when filled with process variables', async () => {
|
||||
|
@@ -40,7 +40,7 @@ declare const adf: any;
|
||||
selector: 'adf-form-field',
|
||||
template: `
|
||||
<div [id]="'field-'+field?.id+'-container'"
|
||||
[hidden]="!field?.isVisible"
|
||||
[style.visibility]="!field?.isVisible ? 'hidden' : 'visible'"
|
||||
[class.adf-focus]="focus"
|
||||
(focusin)="focusToggle()"
|
||||
(focusout)="focusToggle()">
|
||||
|
@@ -43,6 +43,7 @@ import { FormRenderingService } from '../services/form-rendering.service';
|
||||
import { TextWidgetComponent } from './widgets';
|
||||
import { By } from '@angular/platform-browser';
|
||||
import { DebugElement } from '@angular/core';
|
||||
import { FormRulesManager } from '../models/form-rules.model';
|
||||
|
||||
const typeIntoInput = (targetInput: HTMLInputElement, message: string) => {
|
||||
expect(targetInput).toBeTruthy('Expected input to set to be valid and not null');
|
||||
@@ -57,12 +58,12 @@ const typeIntoDate = (targetInput: DebugElement, date: { srcElement: { value: st
|
||||
|
||||
const expectElementToBeHidden = (targetElement: HTMLElement): void => {
|
||||
expect(targetElement).toBeTruthy();
|
||||
expect(targetElement.hidden).toBe(true, `${targetElement.id} should be hidden but it is not`);
|
||||
expect(targetElement.style.visibility).toBe('hidden', `${targetElement.id} should be hidden but it is not`);
|
||||
};
|
||||
|
||||
const expectElementToBeVisible = (targetElement: HTMLElement): void => {
|
||||
expect(targetElement).toBeTruthy();
|
||||
expect(targetElement.hidden).toBe(false, `${targetElement.id} should be visibile but it is not`);
|
||||
expect(targetElement.style.visibility).not.toBe('hidden', `${targetElement.id} should be visibile but it is not`);
|
||||
};
|
||||
|
||||
const expectInputElementValueIs = (targetElement: HTMLInputElement, value: string): void => {
|
||||
@@ -70,22 +71,23 @@ const expectInputElementValueIs = (targetElement: HTMLInputElement, value: strin
|
||||
expect(targetElement.value).toBe(value, `invalid value for ${targetElement.name}`);
|
||||
};
|
||||
|
||||
const expectElementToBeInvalid = (fieldId: string, fixture: ComponentFixture<FormRendererComponent>): void => {
|
||||
const expectElementToBeInvalid = (fieldId: string, fixture: ComponentFixture<FormRendererComponent<any>>): void => {
|
||||
const invalidElementContainer = fixture.nativeElement.querySelector(`#field-${fieldId}-container .adf-invalid`);
|
||||
expect(invalidElementContainer).toBeTruthy();
|
||||
};
|
||||
|
||||
const expectElementToBeValid = (fieldId: string, fixture: ComponentFixture<FormRendererComponent>): void => {
|
||||
const expectElementToBeValid = (fieldId: string, fixture: ComponentFixture<FormRendererComponent<any>>): void => {
|
||||
const invalidElementContainer = fixture.nativeElement.querySelector(`#field-${fieldId}-container .adf-invalid`);
|
||||
expect(invalidElementContainer).toBeFalsy();
|
||||
};
|
||||
|
||||
describe('Form Renderer Component', () => {
|
||||
|
||||
let formRendererComponent: FormRendererComponent;
|
||||
let fixture: ComponentFixture<FormRendererComponent>;
|
||||
let formRendererComponent: FormRendererComponent<any>;
|
||||
let fixture: ComponentFixture<FormRendererComponent<any>>;
|
||||
let formService: FormService;
|
||||
let formRenderingService: FormRenderingService;
|
||||
let rulesManager: FormRulesManager<any>;
|
||||
|
||||
setupTestBed({
|
||||
imports: [
|
||||
@@ -100,6 +102,7 @@ describe('Form Renderer Component', () => {
|
||||
formRendererComponent = fixture.componentInstance;
|
||||
formService = TestBed.inject(FormService);
|
||||
formRenderingService = TestBed.inject(FormRenderingService);
|
||||
rulesManager = fixture.debugElement.injector.get(FormRulesManager);
|
||||
});
|
||||
|
||||
afterEach(() => {
|
||||
@@ -659,4 +662,24 @@ describe('Form Renderer Component', () => {
|
||||
});
|
||||
|
||||
});
|
||||
|
||||
describe('Form rules', () => {
|
||||
it('should call the Form Rules Manager init on component changes', () => {
|
||||
spyOn(rulesManager, 'initialize');
|
||||
const formModel = formService.parseForm(customWidgetFormWithVisibility.formRepresentation.formDefinition);
|
||||
|
||||
formRendererComponent.formDefinition = formModel;
|
||||
formRendererComponent.ngOnChanges();
|
||||
|
||||
expect(rulesManager.initialize).toHaveBeenCalledWith(formModel);
|
||||
});
|
||||
|
||||
it('should call the Form Rules Manager destroy on component destruction', () => {
|
||||
spyOn(rulesManager, 'destroy');
|
||||
|
||||
formRendererComponent.ngOnDestroy();
|
||||
|
||||
expect(rulesManager.destroy).toHaveBeenCalled();
|
||||
});
|
||||
});
|
||||
});
|
||||
|
@@ -15,16 +15,24 @@
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
import { Component, ViewEncapsulation, Input } from '@angular/core';
|
||||
import { Component, ViewEncapsulation, Input, OnDestroy, Injector, OnChanges } from '@angular/core';
|
||||
import { FormRulesManager, formRulesManagerFactory } from '../models/form-rules.model';
|
||||
import { FormModel } from './widgets/core/form.model';
|
||||
|
||||
@Component({
|
||||
selector: 'adf-form-renderer',
|
||||
templateUrl: './form-renderer.component.html',
|
||||
styleUrls: ['./form-renderer.component.scss'],
|
||||
encapsulation: ViewEncapsulation.None
|
||||
encapsulation: ViewEncapsulation.None,
|
||||
providers: [
|
||||
{
|
||||
provide: FormRulesManager,
|
||||
useFactory: formRulesManagerFactory,
|
||||
deps: [Injector]
|
||||
}
|
||||
]
|
||||
})
|
||||
export class FormRendererComponent {
|
||||
export class FormRendererComponent<T> implements OnChanges, OnDestroy {
|
||||
|
||||
/** Toggle debug options. */
|
||||
@Input()
|
||||
@@ -35,4 +43,14 @@ export class FormRendererComponent {
|
||||
|
||||
debugMode: boolean;
|
||||
|
||||
constructor(private formRulesManager: FormRulesManager<T>) { }
|
||||
|
||||
ngOnChanges(): void {
|
||||
this.formRulesManager.initialize(this.formDefinition);
|
||||
}
|
||||
|
||||
ngOnDestroy() {
|
||||
this.formRulesManager.destroy();
|
||||
}
|
||||
|
||||
}
|
||||
|
@@ -24,7 +24,7 @@ import { FormFieldModel } from './form-field.model';
|
||||
import { FormOutcomeModel } from './form-outcome.model';
|
||||
import { FormModel } from './form.model';
|
||||
import { TabModel } from './tab.model';
|
||||
import { fakeMetadataForm, fakeViewerForm } from 'process-services-cloud/src/lib/form/mocks/cloud-form.mock';
|
||||
import { cloudFormMock, fakeMetadataForm, fakeViewerForm } from 'process-services-cloud/src/lib/form/mocks/cloud-form.mock';
|
||||
import { Node } from '@alfresco/js-api';
|
||||
import { UploadWidgetContentLinkModel } from './upload-widget-content-link.model';
|
||||
import { AlfrescoApiService } from '../../../../services';
|
||||
@@ -607,8 +607,8 @@ describe('FormModel', () => {
|
||||
|
||||
expect(form.values['pfx_property_one']).toBe('testValue');
|
||||
expect(form.values['pfx_property_two']).toBe(true);
|
||||
expect(form.values['pfx_property_three']).toEqual({ id: 'opt_1', name: 'Option 1'});
|
||||
expect(form.values['pfx_property_four']).toEqual({ id: 'option_2', name: 'Option: 2'});
|
||||
expect(form.values['pfx_property_three']).toEqual({ id: 'opt_1', name: 'Option 1' });
|
||||
expect(form.values['pfx_property_four']).toEqual({ id: 'option_2', name: 'Option: 2' });
|
||||
expect(form.values['pfx_property_five']).toEqual('green');
|
||||
expect(form.values['pfx_property_six']).toEqual('text-value');
|
||||
expect(form.values['pfx_property_seven']).toBeNull();
|
||||
@@ -649,4 +649,53 @@ describe('FormModel', () => {
|
||||
expect(form.values['cmfb85b2a7295ba41209750bca176ccaf9a']).toBeNull();
|
||||
});
|
||||
});
|
||||
|
||||
describe('Form actions', () => {
|
||||
|
||||
let form: FormModel;
|
||||
let fieldId: string;
|
||||
let field: FormFieldModel;
|
||||
|
||||
beforeEach(() => {
|
||||
form = new FormModel(cloudFormMock);
|
||||
fieldId = 'text1';
|
||||
field = form.getFieldById(fieldId);
|
||||
});
|
||||
|
||||
it('should change field visibility', () => {
|
||||
const originalValue = field.isVisible;
|
||||
|
||||
form.changeFieldVisibility(fieldId, !originalValue);
|
||||
|
||||
expect(field.isVisible).toEqual(!originalValue);
|
||||
});
|
||||
|
||||
it('should change field disabled', () => {
|
||||
const originalValue = field.readOnly;
|
||||
|
||||
form.changeFieldDisabled(fieldId, !originalValue);
|
||||
|
||||
expect(field.readOnly).toEqual(!originalValue);
|
||||
});
|
||||
|
||||
it('should change field required', () => {
|
||||
const originalValue = field.required;
|
||||
|
||||
form.changeFieldRequired(fieldId, !originalValue);
|
||||
|
||||
expect(field.required).toEqual(!originalValue);
|
||||
});
|
||||
|
||||
it('should change field value', () => {
|
||||
form.changeFieldValue(fieldId, 'newValue');
|
||||
|
||||
expect(field.value).toEqual('newValue');
|
||||
});
|
||||
|
||||
it('should change variable value', () => {
|
||||
form.changeVariableValue('FormVarStrId', 'newValue');
|
||||
|
||||
expect(form.getFormVariable('FormVarStrId').value).toEqual('newValue');
|
||||
});
|
||||
});
|
||||
});
|
||||
|
@@ -33,6 +33,7 @@ import { FormFieldTemplates } from './form-field-templates';
|
||||
import { UploadWidgetContentLinkModel } from './upload-widget-content-link.model';
|
||||
import { FormValidationService } from '../../../services/form-validation-service.interface';
|
||||
import { ProcessFormModel } from './process-form-model.interface';
|
||||
import { WidgetTypeEnum, WidgetVisibilityModel } from '../../../models/widget-visibility.model';
|
||||
|
||||
export interface FormRepresentationModel {
|
||||
[key: string]: any;
|
||||
@@ -419,4 +420,44 @@ export class FormModel implements ProcessFormModel {
|
||||
viewer.value = viewer.parseValue(viewer.json);
|
||||
});
|
||||
}
|
||||
|
||||
changeFieldVisibility(fieldId: string, visibility: boolean): void {
|
||||
const visibilityRule: WidgetVisibilityModel = new WidgetVisibilityModel();
|
||||
|
||||
const field = this.getFieldById(fieldId);
|
||||
if (!!field) {
|
||||
visibilityRule.operator = visibility ? 'empty' : '!empty';
|
||||
visibilityRule.leftType = WidgetTypeEnum.field;
|
||||
field.visibilityCondition = visibilityRule;
|
||||
field.isVisible = false;
|
||||
}
|
||||
}
|
||||
|
||||
changeFieldDisabled(fieldId: string, disabled: boolean): void {
|
||||
const field = this.getFieldById(fieldId);
|
||||
if (!!field) {
|
||||
field.readOnly = this.readOnly || disabled;
|
||||
}
|
||||
}
|
||||
|
||||
changeFieldRequired(fieldId: string, required: boolean): void {
|
||||
const field = this.getFieldById(fieldId);
|
||||
if (!!field) {
|
||||
field.required = required;
|
||||
}
|
||||
}
|
||||
|
||||
changeFieldValue(fieldId: string, value: any): void {
|
||||
const field = this.getFieldById(fieldId);
|
||||
if (!!field) {
|
||||
field.value = value;
|
||||
}
|
||||
}
|
||||
|
||||
changeVariableValue(variableId: string, value: any): void {
|
||||
const variable = this.getFormVariable(variableId);
|
||||
if (!!variable) {
|
||||
variable.value = value;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@@ -54,7 +54,16 @@ describe('WidgetComponent', () => {
|
||||
|
||||
element.click();
|
||||
});
|
||||
});
|
||||
|
||||
it('should click event be redirect on the form rules event service', (done) => {
|
||||
widget.formService.formRulesEvent.subscribe((event) => {
|
||||
expect(event.type).toEqual('click');
|
||||
done();
|
||||
});
|
||||
|
||||
element.click();
|
||||
});
|
||||
});
|
||||
|
||||
it('should check field', () => {
|
||||
expect(widget.hasField()).toBeFalsy();
|
||||
@@ -64,7 +73,7 @@ describe('WidgetComponent', () => {
|
||||
|
||||
it('should send an event after view init', (done) => {
|
||||
const fakeForm = new FormModel();
|
||||
const fakeField = new FormFieldModel(fakeForm, {id: 'fakeField', value: 'fakeValue'});
|
||||
const fakeField = new FormFieldModel(fakeForm, { id: 'fakeField', value: 'fakeValue' });
|
||||
widget.field = fakeField;
|
||||
|
||||
widget.fieldChanged.subscribe((field) => {
|
||||
@@ -79,7 +88,7 @@ describe('WidgetComponent', () => {
|
||||
|
||||
it('should send an event when a field is changed', (done) => {
|
||||
const fakeForm = new FormModel();
|
||||
const fakeField = new FormFieldModel(fakeForm, {id: 'fakeField', value: 'fakeValue'});
|
||||
const fakeField = new FormFieldModel(fakeForm, { id: 'fakeField', value: 'fakeValue' });
|
||||
widget.fieldChanged.subscribe((field) => {
|
||||
expect(field).not.toBe(null);
|
||||
expect(field.id).toBe('fakeField');
|
||||
@@ -96,10 +105,10 @@ describe('WidgetComponent', () => {
|
||||
widget.field = new FormFieldModel(null);
|
||||
expect(widget.isRequired()).toBeFalsy();
|
||||
|
||||
widget.field = new FormFieldModel(null, {required: false});
|
||||
widget.field = new FormFieldModel(null, { required: false });
|
||||
expect(widget.isRequired()).toBeFalsy();
|
||||
|
||||
widget.field = new FormFieldModel(null, {required: true});
|
||||
widget.field = new FormFieldModel(null, { required: true });
|
||||
expect(widget.isRequired()).toBeTruthy();
|
||||
});
|
||||
});
|
||||
|
@@ -18,6 +18,8 @@
|
||||
/* eslint-disable @angular-eslint/component-selector */
|
||||
|
||||
import { AfterViewInit, Component, EventEmitter, Input, Output, ViewEncapsulation } from '@angular/core';
|
||||
import { FormFieldEvent } from '../../events/form-field.event';
|
||||
import { FormRulesEvent } from '../../events/form-rules.event';
|
||||
import { FormService } from './../../services/form.service';
|
||||
import { FormFieldModel } from './core/index';
|
||||
|
||||
@@ -106,6 +108,7 @@ export class WidgetComponent implements AfterViewInit {
|
||||
|
||||
event(event: Event): void {
|
||||
this.formService.formEvents.next(event);
|
||||
this.formService.formRulesEvent.next(new FormRulesEvent(event?.type, new FormFieldEvent(this.field?.form, this.field), event));
|
||||
}
|
||||
|
||||
markAsTouched() {
|
||||
|
Reference in New Issue
Block a user