Skip to content

Commit 96bcb63

Browse files
authored
Merge branch 'master' into ibarakov/fix-7090-master
2 parents ee7490b + cabfdde commit 96bcb63

File tree

5 files changed

+92
-42
lines changed

5 files changed

+92
-42
lines changed

CHANGELOG.md

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -4,15 +4,17 @@ All notable changes for each version of this project will be documented in this
44
## 10.2.0
55

66
### General
7+
- `IgxDatePicker`
8+
- Added `aria-labelledby` property for the input field. This will ensure the users of assistive technologies will also know what component is used for, upon input focus.
79
- `IgxInputGroup`
810
- **Breaking Change** - Removed `fluent`, `fluent_search`, `bootstrap`, and `indigo` as possible values for the `type` input property.
911
- **Behavioral Change** - The styling of the input group is now dictated by the theme being used. The remaining `types` - `line`, `border`, and `box` will only have effect on the styling when used with the `material` theme. The `search` type will affect styling when used with all themes. Changing the theme at runtime will not change the styling of the input group, a page refresh is required.
1012
- `IgxOverlay`
1113
- **Breaking Change** - `target` property in `PositionSettings` has been deprecated. You can set the attaching target for the component to show in `OverlaySettings` instead.
1214
- `IgxSelect`
1315
- Added `aria-labelledby` property for the items list container(marked as `role="listbox"`). This will ensure the users of assistive technologies will also know what the list items container is used for, upon opening.
14-
- `IgxDatePicker`
15-
- **Breaking Change** - Deprecated the `label` and `labelVisibility` properties.
16+
- `IgxDatePicker`
17+
- **Breaking Change** - Deprecated the `label` property.
1618

1719

1820
### New Features
@@ -23,7 +25,7 @@ All notable changes for each version of this project will be documented in this
2325
- ` IgxExcelExporterService`
2426
- Added `worksheetName` property to the `IgxExcelExporterOptions`, that allows setting the name of the worksheet.
2527
- `IgxDatePicker`
26-
- The `labelVisibility` and the `label` property have been deprecated and now a custom label is set by nesting a <label igxLabel></label> inside the <igx-date-picker><igx-date-picker> tags.
28+
- The the `label` property have been deprecated and a custom label can also be set by nesting a <label igxLabel></label> inside the <igx-date-picker><igx-date-picker> tags.
2729
- `IgxTimePicker`
2830
- Added a custom label functionality.
2931
- `IgxCalendar` and `IgxDatePicker` - new `showWeekNumbers` input, that allows showing of the week number at left side of content area.

projects/igniteui-angular/src/lib/date-picker/README.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -41,7 +41,7 @@ DatePicker with cancel and today buttons
4141
</igx-date-picker>
4242
```
4343

44-
The DatePicker's custom label can be set in the way shown below. If `labelVisibility` is set to `false` and a custom label is not used, a default one will be set.
44+
The DatePicker's custom label can be set in two ways, either by changing the `label` property or in the way shown below.
4545
````html
4646
<igx-date-picker>
4747
<label igxLabel>Custom label</label>

projects/igniteui-angular/src/lib/date-picker/date-picker.component.html

Lines changed: 2 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -4,12 +4,11 @@
44

55
<ng-template #readOnlyDatePickerTemplate>
66
<igx-input-group (click)="openDialog()">
7-
<label igxLabel *ngIf="!labelDirective&&!labelVisibility">Date</label>
87
<ng-container ngProjectAs="[igxLabel]" *ngTemplateOutlet="labelTemplate"></ng-container>
98
<igx-prefix>
109
<igx-icon>today</igx-icon>
1110
</igx-prefix>
12-
<label *ngIf="labelVisibility&&!labelDirective" igxLabel>{{label}}</label>
11+
<label *ngIf="labelVisibility&&!_labelDirectiveUserTemplate" igxLabel>{{label}}</label>
1312
<input
1413
class="igx-date-picker__input-date"
1514
igxInput
@@ -24,12 +23,11 @@
2423

2524
<ng-template #editableDatePickerTemplate>
2625
<igx-input-group #editableInputGroup>
27-
<label igxLabel *ngIf="!labelDirective&&!labelVisibility">Date</label>
2826
<ng-container ngProjectAs="[igxLabel]" *ngTemplateOutlet="labelTemplate"></ng-container>
2927
<igx-prefix (click)="onOpenClick($event)">
3028
<igx-icon>today</igx-icon>
3129
</igx-prefix>
32-
<label *ngIf="labelVisibility&&!labelDirective" igxLabel>{{label}}</label>
30+
<label *ngIf="labelVisibility&&!_labelDirectiveUserTemplate" igxLabel>{{label}}</label>
3331
<input
3432
class="igx-date-picker__input-date"
3533
igxInput

projects/igniteui-angular/src/lib/date-picker/date-picker.component.spec.ts

Lines changed: 54 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
1-
import { Component, ViewChild, ElementRef, EventEmitter, QueryList } from '@angular/core';
2-
import { async, fakeAsync, TestBed, tick, flush, ComponentFixture } from '@angular/core/testing';
1+
import { Component, ViewChild, ElementRef, EventEmitter, QueryList, Renderer2, DebugElement } from '@angular/core';
2+
import { fakeAsync, TestBed, tick, flush, ComponentFixture, waitForAsync } from '@angular/core/testing';
33
import { FormsModule, FormGroup, FormBuilder, ReactiveFormsModule, Validators, NgControl } from '@angular/forms';
44
import { By } from '@angular/platform-browser';
55
import { NoopAnimationsModule } from '@angular/platform-browser/animations';
@@ -23,7 +23,7 @@ import {
2323

2424
describe('IgxDatePicker', () => {
2525
configureTestSuite();
26-
beforeAll(async(() => {
26+
beforeAll(waitForAsync(() => {
2727
TestBed.configureTestingModule({
2828
declarations: [
2929
IgxDatePickerTestComponent,
@@ -159,7 +159,7 @@ describe('IgxDatePicker', () => {
159159
fixture.detectChanges();
160160

161161
label = fixture.debugElement.query(By.directive(IgxLabelDirective));
162-
expect(label.nativeElement.innerText).toBe('Date');
162+
expect(label).toBeNull();
163163
});
164164

165165
it('When update label property it should reflect on the label text of the datepicker', () => {
@@ -179,7 +179,7 @@ describe('IgxDatePicker', () => {
179179
fixture.detectChanges();
180180

181181
let label = fixture.debugElement.query(By.directive(IgxLabelDirective));
182-
expect(label.nativeElement.innerText).toBe('Date');
182+
expect(label).toBeNull();
183183

184184
fixture.componentInstance.labelVisibility = true;
185185
fixture.detectChanges();
@@ -207,9 +207,9 @@ describe('IgxDatePicker', () => {
207207
fixtureProjectedLabel.detectChanges();
208208
testComponent.customLabelVisibility = false;
209209
fixtureProjectedLabel.detectChanges();
210-
label = dom.query(By.directive(IgxLabelDirective)).nativeElement.innerText;
210+
label = dom.query(By.directive(IgxLabelDirective));
211211
fixtureProjectedLabel.detectChanges();
212-
expect(label).toEqual('Date');
212+
expect(label).toBeNull();
213213

214214
testComponent.customLabelVisibility = true;
215215
fixtureProjectedLabel.detectChanges();
@@ -314,7 +314,43 @@ describe('IgxDatePicker', () => {
314314
const input = fixture.debugElement.query(By.directive(IgxInputDirective)).nativeElement;
315315
expect(input.tabIndex).toBe(3);
316316
});
317+
});
318+
319+
describe('ARIA Tests', () => {
320+
let labelID: string;
321+
let inputLabelledBy: string;
322+
let dom: DebugElement;
323+
324+
it('ARIA Test for a picker with an input group template', () => {
325+
const fixture = TestBed.createComponent(IgxDatePickerRetemplatedComponent);
326+
fixture.detectChanges();
327+
dom = fixture.debugElement;
328+
329+
labelID = dom.query(By.directive(IgxLabelDirective)).nativeElement.id;
330+
inputLabelledBy = dom.query(By.directive(IgxInputDirective)).nativeElement.getAttribute('aria-labelledby');
331+
expect(inputLabelledBy).toEqual(labelID);
332+
});
317333

334+
it('ARIA Test for picker with a dialog mode', () => {
335+
const fixture = TestBed.createComponent(IgxDatePickerTestComponent);
336+
fixture.detectChanges();
337+
dom = fixture.debugElement;
338+
339+
labelID = dom.query(By.directive(IgxLabelDirective)).nativeElement.id;
340+
inputLabelledBy = dom.query(By.directive(IgxInputDirective)).nativeElement.getAttribute('aria-labelledby');
341+
expect(inputLabelledBy).toEqual(labelID);
342+
});
343+
344+
345+
it('ARIA Test for picker with a dropdown mode', () => {
346+
const fixture = TestBed.createComponent(IgxDatePickerOpeningComponent);
347+
fixture.detectChanges();
348+
dom = fixture.debugElement;
349+
350+
labelID = dom.query(By.directive(IgxLabelDirective)).nativeElement.id;
351+
inputLabelledBy = dom.query(By.directive(IgxInputDirective)).nativeElement.getAttribute('aria-labelledby');
352+
expect(inputLabelledBy).toEqual(labelID);
353+
});
318354
});
319355

320356
describe('DatePicker with passed date', () => {
@@ -1453,6 +1489,7 @@ describe('IgxDatePicker', () => {
14531489
let moduleRef;
14541490
let injector;
14551491
let inputGroup: IgxInputGroupComponent;
1492+
let renderer2: Renderer2;
14561493

14571494
beforeEach(() => {
14581495
ngModel = {
@@ -1476,10 +1513,13 @@ describe('IgxDatePicker', () => {
14761513
moduleRef = {};
14771514
injector = { get: () => ngModel };
14781515
inputGroup = new IgxInputGroupComponent(null, null, null, document);
1516+
renderer2 = jasmine.createSpyObj('Renderer2', ['setAttribute'], [{}, 'aria-labelledby', 'test-label-id-1']);
1517+
spyOn(renderer2, 'setAttribute').and.callFake(() => {
1518+
});
14791519
});
14801520

14811521
it('should initialize date picker with required correctly', () => {
1482-
const datePicker = new IgxDatePickerComponent(overlay, element, cdr, moduleRef, injector);
1522+
const datePicker = new IgxDatePickerComponent(overlay, element, cdr, moduleRef, injector, renderer2);
14831523
datePicker['_inputGroup'] = inputGroup;
14841524
datePicker['_inputDirectiveUserTemplates'] = new QueryList();
14851525
spyOnProperty(datePicker, 'inputGroupElement').and.returnValue(null);
@@ -1493,7 +1533,7 @@ describe('IgxDatePicker', () => {
14931533
});
14941534

14951535
it('should initialize date picker with required correctly with user template input-group', () => {
1496-
const datePicker = new IgxDatePickerComponent(overlay, element, cdr, moduleRef, injector);
1536+
const datePicker = new IgxDatePickerComponent(overlay, element, cdr, moduleRef, injector, renderer2);
14971537
datePicker['_inputGroupUserTemplate'] = inputGroup;
14981538
datePicker['_inputDirectiveUserTemplates'] = new QueryList();
14991539
spyOnProperty(datePicker, 'inputGroupElement').and.returnValue(null);
@@ -1507,7 +1547,7 @@ describe('IgxDatePicker', () => {
15071547
});
15081548

15091549
it('should update inputGroup isRequired correctly', () => {
1510-
const datePicker = new IgxDatePickerComponent(overlay, element, cdr, moduleRef, injector);
1550+
const datePicker = new IgxDatePickerComponent(overlay, element, cdr, moduleRef, injector, renderer2);
15111551
datePicker['_inputGroup'] = inputGroup;
15121552
datePicker['_inputDirectiveUserTemplates'] = new QueryList();
15131553
spyOnProperty(datePicker, 'inputGroupElement').and.returnValue(null);
@@ -1619,14 +1659,16 @@ export class IgxDatePickerNgModelComponent {
16191659
<igx-date-picker>
16201660
<ng-template igxDatePickerTemplate let-displayData="displayData">
16211661
<igx-input-group>
1622-
<label igxLabel>Date</label>
1662+
<label igxLabel>Custom Date Label</label>
16231663
<input igxInput [value]="displayData" required />
16241664
</igx-input-group>
16251665
</ng-template>
16261666
</igx-date-picker>
16271667
`
16281668
})
1629-
export class IgxDatePickerRetemplatedComponent { }
1669+
export class IgxDatePickerRetemplatedComponent {
1670+
@ViewChild(IgxDatePickerComponent, { static: true }) public datePicker: IgxDatePickerComponent;
1671+
}
16301672

16311673
@Component({
16321674
template: `

projects/igniteui-angular/src/lib/date-picker/date-picker.component.ts

Lines changed: 30 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,8 @@ import {
2020
Injector,
2121
AfterViewChecked,
2222
ContentChildren,
23-
QueryList
23+
QueryList,
24+
Renderer2
2425
} from '@angular/core';
2526
import { ControlValueAccessor, NG_VALUE_ACCESSOR, NgControl, AbstractControl, NG_VALIDATORS, ValidationErrors } from '@angular/forms';
2627
import {
@@ -32,7 +33,13 @@ import {
3233
isDateInRanges
3334
} from '../calendar/public_api';
3435
import { IgxIconModule } from '../icon/public_api';
35-
import { IgxInputGroupModule, IgxInputDirective, IgxInputGroupComponent, IgxInputState } from '../input-group/public_api';
36+
import {
37+
IgxInputGroupModule,
38+
IgxInputDirective,
39+
IgxInputGroupComponent,
40+
IgxInputState,
41+
IgxLabelDirective
42+
} from '../input-group/public_api';
3643
import { Subject, fromEvent, animationFrameScheduler, interval, Subscription } from 'rxjs';
3744
import { filter, takeUntil, throttle } from 'rxjs/operators';
3845
import { IgxOverlayOutletDirective } from '../directives/toggle/toggle.directive';
@@ -61,7 +68,6 @@ import { IgxDatePickerTemplateDirective, IgxDatePickerActionsDirective } from '.
6168
import { IgxCalendarContainerComponent } from './calendar-container.component';
6269
import { InteractionMode } from '../core/enums';
6370
import { fadeIn, fadeOut } from '../animations/fade';
64-
import { IgxLabelDirective } from '../directives/label/label.directive';
6571
import { DeprecateProperty } from '../core/deprecateDecorators';
6672

6773
let NEXT_ID = 0;
@@ -184,18 +190,7 @@ export class IgxDatePickerComponent implements IDatePicker, ControlValueAccessor
184190
* By default the visibility is set to true.
185191
* @example
186192
* <igx-date-picker [labelVisibility]="false"></igx-date-picker>
187-
* @deprecated Use
188-
* ````html
189-
* <igx-date-picker>
190-
* <label igxLabel>Custom label</label>
191-
* </igx-date-picker>
192-
* ````
193-
* to set a custom label.
194193
*/
195-
@DeprecateProperty(`Deprecated. Use
196-
<igx-date-picker>
197-
<label igxLabel>Custom label</label>
198-
</igx-date-picker> to set a label.` )
199194
@Input()
200195
public labelVisibility = true;
201196

@@ -429,7 +424,10 @@ export class IgxDatePickerComponent implements IDatePicker, ControlValueAccessor
429424
public element: ElementRef,
430425
private _cdr: ChangeDetectorRef,
431426
private _moduleRef: NgModuleRef<any>,
432-
private _injector: Injector) { }
427+
private _injector: Injector,
428+
private _renderer: Renderer2) {
429+
}
430+
433431

434432
/**
435433
* Gets the input group template.
@@ -655,20 +653,14 @@ export class IgxDatePickerComponent implements IDatePicker, ControlValueAccessor
655653
@ViewChild('readOnlyDatePickerTemplate', { read: TemplateRef, static: true })
656654
protected readOnlyDatePickerTemplate: TemplateRef<any>;
657655

658-
/*
659-
* @hidden @internal
660-
*/
661-
@ContentChild(IgxLabelDirective)
662-
public labelDirective: IgxLabelDirective;
663-
664656
/*
665657
* @hidden
666658
*/
667659
@ViewChild('editableDatePickerTemplate', { read: TemplateRef, static: true })
668660
protected editableDatePickerTemplate: TemplateRef<any>;
669661

670662
/*
671-
* @hidden
663+
* @hidden @internal
672664
*/
673665
@ViewChild(IgxInputGroupComponent)
674666
protected _inputGroup: IgxInputGroupComponent;
@@ -688,6 +680,13 @@ export class IgxDatePickerComponent implements IDatePicker, ControlValueAccessor
688680
@ContentChildren(IgxInputDirective, { descendants: true })
689681
private _inputDirectiveUserTemplates: QueryList<IgxInputDirective>;
690682

683+
@ViewChild(IgxLabelDirective)
684+
protected _labelDirective: IgxLabelDirective;
685+
686+
/** @hidden @internal */
687+
@ContentChild(IgxLabelDirective)
688+
public _labelDirectiveUserTemplate: IgxLabelDirective;
689+
691690
/**
692691
* @hidden
693692
*/
@@ -833,6 +832,11 @@ export class IgxDatePickerComponent implements IDatePicker, ControlValueAccessor
833832
return this._inputDirective || this._inputDirectiveUserTemplates.first || null;
834833
}
835834

835+
/** @hidden @internal */
836+
public get labelDirective(): IgxLabelDirective {
837+
return this._labelDirective || this._labelDirectiveUserTemplate || null;
838+
}
839+
836840
/** @hidden @internal */
837841
public ngOnInit(): void {
838842
this._positionSettings = {
@@ -951,6 +955,10 @@ export class IgxDatePickerComponent implements IDatePicker, ControlValueAccessor
951955
}
952956
// TODO: persist validation state when dynamically changing 'dropdown' to 'dialog' ot vice versa.
953957
// For reference -> it is currently persisted if a user template is passed (as template is not recreated)
958+
959+
if (this.labelDirective) {
960+
this._renderer.setAttribute(this.inputDirective.nativeElement, 'aria-labelledby', this.labelDirective.id);
961+
}
954962
}
955963

956964
protected onStatusChanged() {

0 commit comments

Comments
 (0)