[ADF-1653] cleaned user suggestion when input type is an empty string (#2444)

* [ADF-1653] cleaned user suggestion when input type is an empty string

* [ADF-1653] removed wrong fdescribe

* [ADF-1653] improved behaviour of people widget

* Removed fdescribe
This commit is contained in:
Vito
2017-10-06 21:46:43 +01:00
committed by Eugenio Romano
parent fac532faa1
commit 7db1a29f04
6 changed files with 118 additions and 74 deletions
@@ -112,6 +112,10 @@ export class FormFieldModel extends FormWidgetModel {
return this._isValid; return this._isValid;
} }
markAsInvalid() {
this._isValid = false;
}
validate(): boolean { validate(): boolean {
this.validationSummary = null; this.validationSummary = null;
@@ -166,6 +166,10 @@ export class FormModel {
return result; return result;
} }
markAsInvalid() {
this._isValid = false;
}
/** /**
* Validates entire form and all form fields. * Validates entire form and all form fields.
* *
@@ -17,8 +17,7 @@
placeholder="{{field.placeholder}}" placeholder="{{field.placeholder}}"
[mdAutocomplete]="auto"> [mdAutocomplete]="auto">
<md-autocomplete #auto="mdAutocomplete" (optionSelected)="onItemSelect($event.option.value)"> <md-autocomplete #auto="mdAutocomplete" (optionSelected)="onItemSelect($event.option.value)">
<md-option *ngFor="let user of users; let i = index" <md-option *ngFor="let user of users; let i = index" [value]="user">
(click)="onItemClick(user, $event)" [value]="user">
<div class="adf-people-widget-row" id="adf-people-widget-user-{{i}}"> <div class="adf-people-widget-row" id="adf-people-widget-user-{{i}}">
<div class="adf-people-widget-pic"> <div class="adf-people-widget-pic">
{{getInitialUserName(user.firstName, user.lastName)}} {{getInitialUserName(user.firstName, user.lastName)}}
@@ -15,12 +15,15 @@
* limitations under the License. * limitations under the License.
*/ */
import { OverlayContainer } from '@angular/cdk/overlay';
import { async, ComponentFixture, TestBed } from '@angular/core/testing'; import { async, ComponentFixture, TestBed } from '@angular/core/testing';
import { By } from '@angular/platform-browser';
import { CoreModule, LightUserRepresentation } from 'ng2-alfresco-core'; import { CoreModule, LightUserRepresentation } from 'ng2-alfresco-core';
import { Observable } from 'rxjs/Rx'; import { Observable } from 'rxjs/Rx';
import { ActivitiAlfrescoContentService } from '../../../services/activiti-alfresco.service'; import { ActivitiAlfrescoContentService } from '../../../services/activiti-alfresco.service';
import { FormService } from '../../../services/form.service'; import { FormService } from '../../../services/form.service';
import { MaterialModule } from '../../material.module'; import { MaterialModule } from '../../material.module';
import { FormFieldTypes } from '../core/form-field-types';
import { FormFieldModel } from '../core/form-field.model'; import { FormFieldModel } from '../core/form-field.model';
import { FormModel } from '../core/form.model'; import { FormModel } from '../core/form.model';
import { ErrorWidgetComponent } from '../error/error.component'; import { ErrorWidgetComponent } from '../error/error.component';
@@ -33,6 +36,7 @@ describe('PeopleWidgetComponent', () => {
let fixture: ComponentFixture<PeopleWidgetComponent>; let fixture: ComponentFixture<PeopleWidgetComponent>;
let element: HTMLElement; let element: HTMLElement;
let formService: FormService; let formService: FormService;
let overlayContainerElement: HTMLElement;
beforeEach(async(() => { beforeEach(async(() => {
TestBed.configureTestingModule({ TestBed.configureTestingModule({
@@ -47,7 +51,19 @@ describe('PeopleWidgetComponent', () => {
providers: [ providers: [
FormService, FormService,
EcmModelService, EcmModelService,
ActivitiAlfrescoContentService ActivitiAlfrescoContentService,
{provide: OverlayContainer, useFactory: () => {
overlayContainerElement = document.createElement('div');
overlayContainerElement.classList.add('cdk-overlay-container');
document.body.appendChild(overlayContainerElement);
// remove body padding to keep consistent cross-browser
document.body.style.padding = '0';
document.body.style.margin = '0';
return {getContainerElement: () => overlayContainerElement};
}}
] ]
}).compileComponents(); }).compileComponents();
})); }));
@@ -101,20 +117,6 @@ describe('PeopleWidgetComponent', () => {
expect(widget.value).toBe('John Doe'); expect(widget.value).toBe('John Doe');
}); });
it('should prevent default behaviour on option item click', () => {
let event = jasmine.createSpyObj('event', ['preventDefault']);
widget.onItemClick(null, event);
expect(event.preventDefault).toHaveBeenCalled();
});
it('should update values on item click', () => {
let item = new LightUserRepresentation({firstName: 'John', lastName: 'Doe'});
widget.onItemClick(item, null);
expect(widget.field.value).toBe(item);
expect(widget.value).toBe('John Doe');
});
it('should require form field to setup values on init', () => { it('should require form field to setup values on init', () => {
widget.field = null; widget.field = null;
widget.ngOnInit(); widget.ngOnInit();
@@ -204,42 +206,76 @@ describe('PeopleWidgetComponent', () => {
expect(formService.getWorkflowUsers).not.toHaveBeenCalled(); expect(formService.getWorkflowUsers).not.toHaveBeenCalled();
}); });
it('should update form on value flush', () => { it('should reset users when the input field is blank string', () => {
spyOn(widget.field, 'updateForm').and.callThrough(); let fakeUser = new LightUserRepresentation({id: '1', email: 'ffff@fff'});
widget.flushValue(); widget.users.push(fakeUser);
expect(widget.field.updateForm).toHaveBeenCalled();
let keyboardEvent = new KeyboardEvent('keypress');
widget.value = '';
widget.onKeyUp(keyboardEvent);
expect(widget.users).toEqual([]);
}); });
it('should flush value and update field', () => { describe('when template is ready', () => {
widget.users = [
new LightUserRepresentation({firstName: 'Tony', lastName: 'Stark'}),
new LightUserRepresentation({firstName: 'John', lastName: 'Doe'})
];
widget.value = 'John Doe';
widget.flushValue();
expect(widget.value).toBe('John Doe'); let fakeUserResult = [
expect(widget.field.value).toBe(widget.users[1]); { id: 1001, firstName: 'Test01', lastName: 'Test01', email: 'test' },
{ id: 1002, firstName: 'Test02', lastName: 'Test02', email: 'test2' }];
beforeEach(async(() => {
spyOn(formService, 'getWorkflowUsers').and.returnValue(Observable.create(observer => {
observer.next(fakeUserResult);
observer.complete();
}));
widget.field = new FormFieldModel(new FormModel({ taskId: 'fake-task-id' }), {
id: 'people-id',
name: 'people-name',
type: FormFieldTypes.PEOPLE,
readOnly: false
});
fixture.detectChanges();
element = fixture.nativeElement;
}));
afterEach(() => {
fixture.destroy();
TestBed.resetTestingModule();
}); });
it('should be case insensitive when flushing field', () => { it('should render the people component', () => {
widget.users = [ expect(element.querySelector('#people-widget-content')).not.toBeNull();
new LightUserRepresentation({firstName: 'Tony', lastName: 'Stark'}),
new LightUserRepresentation({firstName: 'John', lastName: 'Doe'})
];
widget.value = 'TONY sTaRk';
widget.flushValue();
expect(widget.value).toBe('Tony Stark');
expect(widget.field.value).toBe(widget.users[0]);
}); });
it('should reset value and field on flush', () => { it('should show an error message if the user is invalid', async(() => {
widget.value = 'Missing User'; let peopleHTMLElement: HTMLInputElement = <HTMLInputElement> element.querySelector('#people-id');
widget.field.value = {}; peopleHTMLElement.focus();
widget.flushValue(); widget.value = 'K';
peopleHTMLElement.value = 'K';
peopleHTMLElement.dispatchEvent(new Event('keyup'));
peopleHTMLElement.dispatchEvent(new Event('input'));
fixture.detectChanges();
fixture.whenStable().then(() => {
expect(element.querySelector('.adf-error-text')).not.toBeNull();
expect(element.querySelector('.adf-error-text').textContent).toContain('Invalid value provided');
});
}));
expect(widget.value).toBeNull(); it('should show the people if the typed result match', async(() => {
expect(widget.field.value).toBeNull(); let peopleHTMLElement: HTMLInputElement = <HTMLInputElement> element.querySelector('#people-id');
peopleHTMLElement.focus();
widget.value = 'T';
peopleHTMLElement.value = 'T';
peopleHTMLElement.dispatchEvent(new Event('keyup'));
peopleHTMLElement.dispatchEvent(new Event('input'));
fixture.detectChanges();
fixture.whenStable().then(() => {
fixture.detectChanges();
expect(fixture.debugElement.query(By.css('#adf-people-widget-user-0'))).not.toBeNull();
expect(fixture.debugElement.query(By.css('#adf-people-widget-user-1'))).not.toBeNull();
}); });
}));
});
}); });
@@ -71,30 +71,41 @@ export class PeopleWidgetComponent extends WidgetComponent implements OnInit {
} }
} }
} }
if (this.isValueDefined() && this.value.trim().length === 0) {
this.oldValue = this.value;
this.field.validationSummary = '';
this.users = [];
}
}
isValueDefined() {
return this.value !== null && this.value !== undefined;
} }
searchUsers() { searchUsers() {
this.formService.getWorkflowUsers(this.value, this.groupId) this.formService.getWorkflowUsers(this.value, this.groupId)
.subscribe((result: LightUserRepresentation[]) => { .subscribe((result: LightUserRepresentation[]) => {
this.users = result || []; this.users = result || [];
this.validateValue();
}); });
} }
flushValue() { validateValue() {
let option = this.users.find(item => { let validUserName = this.getUserFromValue();
let fullName = this.getDisplayName(item).toLocaleLowerCase(); if (validUserName) {
return (this.value && fullName === this.value.toLocaleLowerCase()); this.field.validationSummary = '';
}); this.field.value = validUserName;
this.value = this.getDisplayName(validUserName);
if (option) {
this.field.value = option;
this.value = this.getDisplayName(option);
} else { } else {
this.field.value = null; this.field.value = '';
this.value = null; this.field.validationSummary = 'Invalid value provided';
this.field.markAsInvalid();
this.field.form.markAsInvalid();
}
} }
this.field.updateForm(); getUserFromValue() {
return this.users.find((user) => this.getDisplayName(user).toLocaleLowerCase() === this.value.toLocaleLowerCase());
} }
getDisplayName(model: LightUserRepresentation) { getDisplayName(model: LightUserRepresentation) {
@@ -102,20 +113,9 @@ export class PeopleWidgetComponent extends WidgetComponent implements OnInit {
let displayName = `${model.firstName || ''} ${model.lastName || ''}`; let displayName = `${model.firstName || ''} ${model.lastName || ''}`;
return displayName.trim(); return displayName.trim();
} }
return ''; return '';
} }
onItemClick(item: LightUserRepresentation, event: Event) {
if (item) {
this.field.value = item;
this.value = this.getDisplayName(item);
}
if (event) {
event.preventDefault();
}
}
onItemSelect(item: LightUserRepresentation) { onItemSelect(item: LightUserRepresentation) {
if (item) { if (item) {
this.field.value = item; this.field.value = item;
@@ -387,6 +387,7 @@ export class FormService {
return Observable.of(user); return Observable.of(user);
}) })
.combineAll() .combineAll()
.defaultIfEmpty([])
.catch(err => this.handleError(err)); .catch(err => this.handleError(err));
} }