Skip to content

Commit d1b7124

Browse files
alinelariguetjhosefmarks
authored andcommitted
fix(multiselect): corrige disparo do evento de change na inicialização
Corrige disparo indesejado do evento de change na inicialização do componente. Fixes DTHFUI-2524
1 parent e632fbc commit d1b7124

File tree

2 files changed

+53
-67
lines changed

2 files changed

+53
-67
lines changed

projects/ui/src/lib/components/po-field/po-multiselect/po-multiselect-base.component.spec.ts

Lines changed: 37 additions & 39 deletions
Original file line numberDiff line numberDiff line change
@@ -28,9 +28,9 @@ describe('PoMultiselectBaseComponent:', () => {
2828
expectSettersMethod(component, 'required', 'undefined', 'required', false);
2929
expectSettersMethod(component, 'required', undefined, 'required', false);
3030

31-
spyOn(component, 'updateModelToValidate');
31+
spyOn(component, <any>'validateModel');
3232
component.disabled = true;
33-
expect(component.updateModelToValidate).toHaveBeenCalled();
33+
expect(component['validateModel']).toHaveBeenCalled();
3434
});
3535

3636
it('should set disabled', () => {
@@ -42,10 +42,10 @@ describe('PoMultiselectBaseComponent:', () => {
4242
expectSettersMethod(component, 'disabled', 'undefined', 'disabled', false);
4343
expectSettersMethod(component, 'disabled', undefined, 'disabled', false);
4444

45-
spyOn(component, 'updateModelToValidate');
45+
spyOn(component, <any>'validateModel');
4646
spyOn(component, 'updateVisibleItems');
4747
component.disabled = true;
48-
expect(component.updateModelToValidate).toHaveBeenCalled();
48+
expect(component['validateModel']).toHaveBeenCalled();
4949
expect(component.updateVisibleItems).toHaveBeenCalled();
5050
});
5151

@@ -107,12 +107,6 @@ describe('PoMultiselectBaseComponent:', () => {
107107
expect(component.updateList).toHaveBeenCalledWith([]);
108108
});
109109

110-
it('should set variable readyToValidation to true', () => {
111-
component['readyToValidation'] = false;
112-
component.ngAfterContentChecked();
113-
expect(component['readyToValidation']).toBeTruthy();
114-
});
115-
116110
it('should call validation functions and sort function', () => {
117111
component.options = [{label: '1', value: 1}];
118112
component.sort = true;
@@ -177,25 +171,6 @@ describe('PoMultiselectBaseComponent:', () => {
177171
expect(component.visibleOptionsDropdown.length).toBe(1);
178172
});
179173

180-
it('should call method callOnChange with selectedOptions', fakeAsync(() => {
181-
component['readyToValidation'] = true;
182-
component['selectedOptions'] = [];
183-
spyOn(component, 'callOnChange');
184-
component.updateModelToValidate();
185-
186-
tick(100);
187-
expect(component.callOnChange).toHaveBeenCalledWith([]);
188-
}));
189-
190-
it('shouldn`t call method callOnChange', fakeAsync(() => {
191-
component['readyToValidation'] = false;
192-
spyOn(component, 'callOnChange');
193-
component.updateModelToValidate();
194-
195-
tick(100);
196-
expect(component.callOnChange).not.toHaveBeenCalled();
197-
}));
198-
199174
it('should call onModelChange and eventChange', () => {
200175
const fakeThis = {
201176
onModelChange: v => {},
@@ -343,16 +318,6 @@ describe('PoMultiselectBaseComponent:', () => {
343318
expect(component.selectedOptions.length).toBe(1);
344319
});
345320

346-
it('should call `callOnChange` and `updateSelectedOptions` with `[]` if model value is `invalid`.', () => {
347-
spyOn(component, 'updateSelectedOptions');
348-
spyOn(component, 'callOnChange');
349-
350-
component.writeValue(null);
351-
352-
expect(component.updateSelectedOptions).toHaveBeenCalledWith([]);
353-
expect(component.callOnChange).toHaveBeenCalledWith([]);
354-
});
355-
356321
it('should update model if the values is different of the selectedOptions.', () => {
357322
component.selectedOptions = [];
358323
component.options = [{value: 1, label: '1'}, {value: 2, label: '2'}];
@@ -401,6 +366,39 @@ describe('PoMultiselectBaseComponent:', () => {
401366
component.eventChange([{value: 1, label : '1'}]);
402367
expect(component.change.emit).not.toHaveBeenCalled();
403368
});
369+
370+
it('registerOnValidatorChange: should register validatorChange function', () => {
371+
const registerOnValidatorChangeFn = () => {};
372+
373+
component.registerOnValidatorChange(registerOnValidatorChangeFn);
374+
expect(component['validatorChange']).toBe(registerOnValidatorChangeFn);
375+
});
376+
377+
it('validateModel: shouldn`t call `validatorChange` when it is falsy', () => {
378+
component['validatorChange'] = undefined;
379+
380+
component['validateModel']();
381+
382+
expect(component['validatorChange']).toBeUndefined();
383+
});
384+
385+
it('validateModel: should call `validatorChange` to validateModel when `validatorChange` is a function', () => {
386+
component['validatorChange'] = () => {};
387+
388+
spyOn(component, <any> 'validatorChange');
389+
390+
component['validateModel']();
391+
392+
expect(component['validatorChange']).toHaveBeenCalledWith();
393+
});
394+
395+
it('writeValue: should call `updateSelectedOptions` with `[]` if model value is `invalid`.', () => {
396+
spyOn(component, 'updateSelectedOptions');
397+
398+
component.writeValue(null);
399+
400+
expect(component.updateSelectedOptions).toHaveBeenCalledWith([]);
401+
});
404402
});
405403

406404
describe('Properties:', () => {

projects/ui/src/lib/components/po-field/po-multiselect/po-multiselect-base.component.ts

Lines changed: 16 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
import { AfterContentChecked, EventEmitter, Input, OnInit, Output } from '@angular/core';
1+
import { EventEmitter, Input, OnInit, Output } from '@angular/core';
22
import { AbstractControl, ControlValueAccessor, Validator } from '@angular/forms';
33

44
import { browserLanguage, convertToBoolean, removeDuplicatedOptions, removeUndefinedAndNullOptions, sortOptionsByProperty,
@@ -40,7 +40,7 @@ export const poMultiselectLiteralsDefault = {
4040
* Este componente também não deve ser utilizado em casos onde a seleção seja única. Nesses casos, deve-se utilizar o
4141
* po-select, po-combo ou po-radio-group.
4242
*/
43-
export abstract class PoMultiselectBaseComponent implements AfterContentChecked, ControlValueAccessor, OnInit, Validator {
43+
export abstract class PoMultiselectBaseComponent implements ControlValueAccessor, OnInit, Validator {
4444

4545
private _autofocus?: boolean = false;
4646
private _disabled?: boolean = false;
@@ -55,7 +55,7 @@ export abstract class PoMultiselectBaseComponent implements AfterContentChecked,
5555
private onModelChange: any;
5656
// tslint:disable-next-line
5757
private onModelTouched: any;
58-
private readyToValidation = false;
58+
private validatorChange: any;
5959

6060
selectedOptions: Array<PoMultiselectOption> = [];
6161
visibleOptionsDropdown: Array<PoMultiselectOption> = [];
@@ -159,7 +159,7 @@ export abstract class PoMultiselectBaseComponent implements AfterContentChecked,
159159
*/
160160
@Input('p-required') set required(required: boolean) {
161161
this._required = <any>required === '' ? true : convertToBoolean(required);
162-
this.updateModelToValidate();
162+
this.validateModel();
163163
}
164164

165165
get required() {
@@ -177,7 +177,7 @@ export abstract class PoMultiselectBaseComponent implements AfterContentChecked,
177177
*/
178178
@Input('p-disabled') set disabled(disabled: boolean) {
179179
this._disabled = <any>disabled === '' ? true : convertToBoolean(disabled);
180-
this.updateModelToValidate();
180+
this.validateModel();
181181

182182
this.updateVisibleItems();
183183
}
@@ -295,13 +295,6 @@ export abstract class PoMultiselectBaseComponent implements AfterContentChecked,
295295
this.updateList(this.options);
296296
}
297297

298-
ngAfterContentChecked() {
299-
// Seta esta variável para indicar que a tela já foi carregada e podem ser aplicadas as validações.
300-
// A partir desse momento, toda vez que uma propriedade que interfere na validação, for alterada, o model será atualizado
301-
// para que o campo seja validado novamente.
302-
this.readyToValidation = true;
303-
}
304-
305298
validAndSortOptions() {
306299
if (this.options && this.options.length) {
307300

@@ -329,18 +322,6 @@ export abstract class PoMultiselectBaseComponent implements AfterContentChecked,
329322
}
330323
}
331324

332-
// Emite a atualização do model caso esta propriedade seja alterada dinamicamente.
333-
updateModelToValidate() {
334-
if (this.readyToValidation) {
335-
336-
// Este timeout é necessário para quando for atualizado o model e uma propriedade do Datepicker ao mesmo tempo.
337-
// Caso contrário, o writeValue não é disparado, não atualizando o model do componente.
338-
setTimeout(() => {
339-
this.callOnChange(this.selectedOptions);
340-
});
341-
}
342-
}
343-
344325
callOnChange(selectedOptions: Array<PoMultiselectOption>) {
345326
if (this.onModelChange) {
346327
this.onModelChange(this.getValuesFromOptions(selectedOptions));
@@ -429,10 +410,7 @@ export abstract class PoMultiselectBaseComponent implements AfterContentChecked,
429410
}
430411

431412
writeValue(values: any): void {
432-
if (!values) {
433-
values = [];
434-
this.callOnChange([]);
435-
}
413+
values = values || [];
436414

437415
// Validar se todos os items existem entre os options, senão atualizar o model
438416
this.updateSelectedOptions(values);
@@ -450,6 +428,16 @@ export abstract class PoMultiselectBaseComponent implements AfterContentChecked,
450428
this.onModelTouched = fn;
451429
}
452430

431+
registerOnValidatorChange(fn: () => void) {
432+
this.validatorChange = fn;
433+
}
434+
435+
private validateModel() {
436+
if (this.validatorChange) {
437+
this.validatorChange();
438+
}
439+
}
440+
453441
abstract updateVisibleItems(): void;
454442

455443
}

0 commit comments

Comments
 (0)