Skip to content

Commit edd6927

Browse files
committed
Merge branch '8.2.x' of https://github.com/IgniteUI/igniteui-angular into mdragnev/fix-6467-8.2.x
2 parents d02eed3 + 4a79c1d commit edd6927

File tree

5 files changed

+99
-14
lines changed

5 files changed

+99
-14
lines changed

projects/igniteui-angular/src/lib/select/select.component.html

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@
1616
[attr.aria-owns]="this.listId"
1717
[attr.aria-activedescendant]="!this.collapsed ? this.focusedItem?.id : null"
1818
(blur)="onBlur()"
19+
(focus)="onFocus()"
1920
/>
2021
<ng-container ngProjectAs="igx-suffix">
2122
<ng-content select="igx-suffix,[igxSuffix]"></ng-content>

projects/igniteui-angular/src/lib/select/select.component.spec.ts

Lines changed: 71 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,9 @@
11
import { IgxInputState } from './../directives/input/input.directive';
22
import { Component, ViewChild, DebugElement } from '@angular/core';
33
import { async, TestBed, tick, fakeAsync } from '@angular/core/testing';
4-
import { FormsModule, FormGroup, FormBuilder, FormControl, Validators, ReactiveFormsModule, NgForm } from '@angular/forms';
4+
import { FormsModule, FormGroup, FormBuilder, FormControl, Validators, ReactiveFormsModule, NgForm, NgControl } from '@angular/forms';
55
import { By } from '@angular/platform-browser';
6-
import { IgxDropDownModule } from '../drop-down/index';
6+
import { IgxDropDownModule, IgxDropDownItemComponent } from '../drop-down/index';
77
import { IgxIconModule } from '../icon/index';
88
import { IgxInputGroupModule } from '../input-group/index';
99
import { NoopAnimationsModule } from '@angular/platform-browser/animations';
@@ -604,6 +604,24 @@ describe('igxSelect', () => {
604604
expect(inputGroupWithRequiredAsterisk).toBeDefined();
605605
}));
606606

607+
it('Should have correctly bound focus and blur handlers', () => {
608+
const fix = TestBed.createComponent(IgxSelectTemplateFormComponent);
609+
fix.detectChanges();
610+
select = fix.componentInstance.select;
611+
const input = fix.debugElement.query(By.css(`.${CSS_CLASS_INPUT}`));
612+
613+
spyOn(select, 'onFocus');
614+
spyOn(select, 'onBlur');
615+
616+
input.triggerEventHandler('focus', {});
617+
expect(select.onFocus).toHaveBeenCalled();
618+
expect(select.onFocus).toHaveBeenCalledWith();
619+
620+
input.triggerEventHandler('blur', {});
621+
expect(select.onBlur).toHaveBeenCalled();
622+
expect(select.onFocus).toHaveBeenCalledWith();
623+
});
624+
607625
// Bug #6025 Select does not disable in reactive form
608626
it('Should disable when form is disabled', fakeAsync(() => {
609627
const fix = TestBed.createComponent(IgxSelectReactiveFormComponent);
@@ -2394,6 +2412,57 @@ describe('igxSelect', () => {
23942412
});
23952413
});
23962414

2415+
describe('igxSelect ControlValueAccessor Unit', () => {
2416+
let select: IgxSelectComponent;
2417+
it('Should correctly implement interface methods', () => {
2418+
const mockSelection = jasmine.createSpyObj('IgxSelectionAPIService', ['get', 'set', 'clear', 'first_item']);
2419+
const mockCdr = jasmine.createSpyObj('ChangeDetectorRef', ['detectChanges']);
2420+
const mockNgControl = jasmine.createSpyObj('NgControl', ['registerOnChangeCb', 'registerOnTouchedCb']);
2421+
const mockInjector = jasmine.createSpyObj('Injector', {
2422+
'get': mockNgControl
2423+
});
2424+
2425+
// init
2426+
select = new IgxSelectComponent(null, mockCdr, mockSelection, null, mockInjector);
2427+
select.ngOnInit();
2428+
select.registerOnChange(mockNgControl.registerOnChangeCb);
2429+
select.registerOnTouched(mockNgControl.registerOnTouchedCb);
2430+
expect(mockInjector.get).toHaveBeenCalledWith(NgControl, null);
2431+
2432+
// writeValue
2433+
expect(select.value).toBeUndefined();
2434+
select.writeValue('test');
2435+
expect(mockSelection.clear).toHaveBeenCalled();
2436+
expect(select.value).toBe('test');
2437+
2438+
// setDisabledState
2439+
select.setDisabledState(true);
2440+
expect(select.disabled).toBe(true);
2441+
select.setDisabledState(false);
2442+
expect(select.disabled).toBe(false);
2443+
2444+
// OnChange callback
2445+
const item = new IgxDropDownItemComponent(select, null, null, mockSelection);
2446+
item.value = 'itemValue';
2447+
select.selectItem(item);
2448+
expect(mockSelection.set).toHaveBeenCalledWith(select.id, new Set([item]));
2449+
expect(mockNgControl.registerOnChangeCb).toHaveBeenCalledWith('itemValue');
2450+
2451+
// OnTouched callback
2452+
select.onFocus();
2453+
expect(mockNgControl.registerOnTouchedCb).toHaveBeenCalledTimes(1);
2454+
2455+
select.input = {} as any;
2456+
spyOnProperty(select, 'collapsed').and.returnValue(true);
2457+
select.onBlur();
2458+
expect(mockNgControl.registerOnTouchedCb).toHaveBeenCalledTimes(2);
2459+
});
2460+
2461+
it('Should correctly handle ngControl validity', () => {
2462+
pending('Convert existing form test here');
2463+
});
2464+
});
2465+
23972466
@Component({
23982467
template: `
23992468
<igx-select #select [width]="'300px'" [height]="'200px'" [placeholder]="'Choose a city'" [(ngModel)]="value">

projects/igniteui-angular/src/lib/select/select.component.ts

Lines changed: 14 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -202,8 +202,12 @@ export class IgxSelectComponent extends IgxDropDownComponent implements IgxSelec
202202
super(elementRef, cdr, selection, _displayDensityOptions);
203203
}
204204

205+
//#region ControlValueAccessor
206+
205207
/** @hidden @internal */
206208
private _onChangeCallback: (_: any) => void = noop;
209+
/** @hidden @internal */
210+
private _onTouchedCallback: () => void = noop;
207211

208212
/** @hidden @internal */
209213
public writeValue = (value: any) => {
@@ -216,12 +220,15 @@ export class IgxSelectComponent extends IgxDropDownComponent implements IgxSelec
216220
}
217221

218222
/** @hidden @internal */
219-
public registerOnTouched(fn: any): void { }
223+
public registerOnTouched(fn: any): void {
224+
this._onTouchedCallback = fn;
225+
}
220226

221227
/** @hidden @internal */
222228
public setDisabledState(isDisabled: boolean): void {
223229
this.disabled = isDisabled;
224230
}
231+
//#endregion
225232

226233
/** @hidden @internal */
227234
public getEditElement(): HTMLElement {
@@ -325,6 +332,7 @@ export class IgxSelectComponent extends IgxDropDownComponent implements IgxSelec
325332

326333
/** @hidden @internal */
327334
public onBlur(): void {
335+
this._onTouchedCallback();
328336
if (this.ngControl && !this.ngControl.valid) {
329337
this.input.valid = IgxInputState.INVALID;
330338
} else {
@@ -335,6 +343,11 @@ export class IgxSelectComponent extends IgxDropDownComponent implements IgxSelec
335343
}
336344
}
337345

346+
/** @hidden @internal */
347+
public onFocus(): void {
348+
this._onTouchedCallback();
349+
}
350+
338351
protected onStatusChanged() {
339352
if ((this.ngControl.control.touched || this.ngControl.control.dirty) &&
340353
(this.ngControl.control.validator || this.ngControl.control.asyncValidator)) {

src/app/select/select.sample.html

Lines changed: 8 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,8 @@ <h4 class="sample-title">Select with ngModel, set items OnInit</h4>
88
[required]="true"
99
[placeholder]="'Pick One'"
1010
[(ngModel)]="value"
11+
[ngModelOptions]="{updateOn: 'blur'}" #selectModel="ngModel"
12+
required
1113
(onOpening)="testOnOpening($event)"
1214
(onOpened)="testOnOpened()"
1315
(onClosing)="testOnClosing($event)"
@@ -24,12 +26,15 @@ <h4 class="sample-title">Select with ngModel, set items OnInit</h4>
2426
{{ item.field }}
2527
</igx-select-item>
2628
</igx-select>
29+
<div>Model: {{selectModel.value}}</div>
2730

2831
<div>
2932
<h4>Display Density</h4>
30-
<button igxButton="raised" [disabled]="selectDisplayDensity.displayDensity === compact" (click)="setDensity(compact)">Compact</button>
31-
<button igxButton="raised" [disabled]="selectDisplayDensity.displayDensity === cosy" (click)="setDensity(cosy)">Cosy</button>
32-
<button igxButton="raised" [disabled]="selectDisplayDensity.displayDensity === comfortable" (click)="setDensity(comfortable)">Comfortable</button>
33+
<igx-buttongroup (onSelect)="setDensity($event)">
34+
<button igxButton value="compact">Compact</button>
35+
<button igxButton value="cosy">Cosy</button>
36+
<button igxButton value="comfortable">Comfortable</button>
37+
</igx-buttongroup>
3338
</div>
3439

3540
<h4 class="sample-title">Select - declare items in html template</h4>

src/app/select/select.sample.ts

Lines changed: 5 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,8 @@ import {
55
HorizontalAlignment, VerticalAlignment, scaleInTop, scaleOutBottom, ConnectedPositioningStrategy,
66
AbsoluteScrollStrategy,
77
IgxSelectComponent,
8-
DisplayDensity
8+
DisplayDensity,
9+
IButtonGroupEventArgs
910
} from 'igniteui-angular';
1011

1112
@Component({
@@ -23,10 +24,6 @@ export class SelectSampleComponent implements OnInit {
2324
@ViewChild('displayDensitySelect', { read: IgxSelectComponent, static: true })
2425
public selectDisplayDensity: IgxSelectComponent;
2526

26-
public comfortable = DisplayDensity.comfortable;
27-
public cosy = DisplayDensity.cosy;
28-
public compact = DisplayDensity.compact;
29-
3027
constructor(fb: FormBuilder) {
3128
this.reactiveForm = fb.group({
3229
'citiesSelect': ['', Validators.required]
@@ -64,7 +61,7 @@ export class SelectSampleComponent implements OnInit {
6461
public onSubmitReactive() { }
6562

6663
public selectBanana() {
67-
this.selectFruits.selectItem(this.selectFruits.items[3]);
64+
this.selectFruits.setSelectedItem(3);
6865
}
6966

7067
public setToNull() {
@@ -144,7 +141,7 @@ export class SelectSampleComponent implements OnInit {
144141
}
145142
}
146143

147-
setDensity(density: DisplayDensity) {
148-
this.selectDisplayDensity.displayDensity = density;
144+
setDensity(event: IButtonGroupEventArgs) {
145+
this.selectDisplayDensity.displayDensity = event.button.nativeElement.value;
149146
}
150147
}

0 commit comments

Comments
 (0)