Skip to content

Commit 9018e5a

Browse files
SAndreevabkulov
authored andcommitted
Time picker: add hour/minute only mode (#4939)
* feat(time picker): add hour/minute mode #4679 * chore(*): fix lint errors #4679 * chore(*): bug fixing/improvements #4679 * chore(*): fix lint error #4679 * chore(*): address some review comments #4679 * chore(*): Address more review comments #4679
1 parent 2b2c335 commit 9018e5a

9 files changed

+474
-87
lines changed

projects/igniteui-angular/src/lib/directives/mask/mask.directive.ts

+13-1
Original file line numberDiff line numberDiff line change
@@ -60,7 +60,14 @@ export class IgxMaskDirective implements OnInit, ControlValueAccessor {
6060
* @memberof IgxMaskDirective
6161
*/
6262
@Input()
63-
public placeholder: string;
63+
public set placeholder(val: string) {
64+
this._placeholder = val;
65+
this.nativeElement.setAttribute('placeholder', this._placeholder);
66+
}
67+
68+
public get placeholder(): string {
69+
return this._placeholder;
70+
}
6471

6572
/**
6673
* Specifies a pipe to be used on blur.
@@ -148,6 +155,11 @@ export class IgxMaskDirective implements OnInit, ControlValueAccessor {
148155
*/
149156
private _selection: number;
150157

158+
/**
159+
*@hidden
160+
*/
161+
private _placeholder: string;
162+
151163
/**
152164
*@hidden
153165
*/

projects/igniteui-angular/src/lib/time-picker/time-picker.common.ts

+3-1
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,6 @@ export const IGX_TIME_PICKER_COMPONENT = 'IgxTimePickerComponentToken';
66

77
/** @hidden */
88
export interface IgxTimePickerBase {
9-
_ampmItems: any[];
109
hourList: ElementRef;
1110
minuteList: ElementRef;
1211
ampmList: ElementRef;
@@ -17,6 +16,9 @@ export interface IgxTimePickerBase {
1716
promptChar: string;
1817
cleared: boolean;
1918
mode: InteractionMode;
19+
showHoursList: boolean;
20+
showMinutesList: boolean;
21+
showAmPmList: boolean;
2022
nextHour();
2123
prevHour();
2224
nextMinute();

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

+3-3
Original file line numberDiff line numberDiff line change
@@ -34,13 +34,13 @@ <h2 class="igx-time-picker__header-hour">
3434
</div>
3535
<div class="igx-time-picker__main">
3636
<div class="igx-time-picker__body">
37-
<div #hourList [igxItemList]="'hourList'">
37+
<div *ngIf="showHoursList" #hourList [igxItemList]="'hourList'">
3838
<span [igxHourItem]="hour" *ngFor="let hour of hourView">{{ hour }}</span>
3939
</div>
40-
<div #minuteList [igxItemList]="'minuteList'">
40+
<div *ngIf="showMinutesList" #minuteList [igxItemList]="'minuteList'">
4141
<span [igxMinuteItem]="minute" *ngFor="let minute of minuteView">{{ minute }}</span>
4242
</div>
43-
<div #ampmList [igxItemList]="'ampmList'">
43+
<div *ngIf="showAmPmList" #ampmList [igxItemList]="'ampmList'">
4444
<span [igxAmPmItem]="ampm" *ngFor="let ampm of ampmView">{{ ampm }}</span>
4545
</div>
4646
</div>

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

+239-2
Original file line numberDiff line numberDiff line change
@@ -616,7 +616,7 @@ describe('IgxTimePicker', () => {
616616
const selectHour = hourColumn.children[3];
617617
const AMPMColumn: any = dom.query(By.css('.igx-time-picker__ampmList'));
618618

619-
expect(AMPMColumn.children.length).toBe(0);
619+
expect(AMPMColumn).toBeNull();
620620
expect(selectHour.nativeElement.innerText).toBe('00');
621621
}));
622622

@@ -1446,6 +1446,242 @@ describe('IgxTimePicker', () => {
14461446
expect(dropdownClientRect.left).toEqual(inputGroupClientRect.left);
14471447
}));
14481448
});
1449+
1450+
describe('Hour/minute only mode', () => {
1451+
configureTestSuite();
1452+
let fixture, timePicker, dom, input;
1453+
1454+
beforeEach(
1455+
async(() => {
1456+
fixture = TestBed.createComponent(IgxTimePickerDropDownSingleHourComponent);
1457+
fixture.detectChanges();
1458+
1459+
timePicker = fixture.componentInstance.timePicker;
1460+
dom = fixture.debugElement;
1461+
input = dom.query(By.directive(IgxInputDirective));
1462+
})
1463+
);
1464+
1465+
afterEach(async(() => {
1466+
UIInteractions.clearOverlay();
1467+
}));
1468+
1469+
it('Should render dropdown and input group correctly when format conatains only hours.', fakeAsync(() => {
1470+
fixture.componentInstance.format = 'hh tt';
1471+
fixture.componentInstance.customDate = new Date(2018, 10, 27, 17, 45, 0, 0);
1472+
fixture.detectChanges();
1473+
1474+
const iconTime = dom.queryAll(By.css('.igx-icon'))[0];
1475+
1476+
UIInteractions.clickElement(iconTime);
1477+
tick();
1478+
fixture.detectChanges();
1479+
1480+
const hourColumn = dom.query(By.css('.igx-time-picker__hourList'));
1481+
const minuteColumn = dom.query(By.css('.igx-time-picker__minuteList'));
1482+
const ampmColumn = dom.query(By.css('.igx-time-picker__ampmList'));
1483+
1484+
expect(hourColumn).not.toBeNull();
1485+
expect(ampmColumn).not.toBeNull();
1486+
expect(minuteColumn).toBeNull();
1487+
}));
1488+
1489+
it('Should mask editable input correctly when format conatains only hours.', fakeAsync(() => {
1490+
fixture.componentInstance.format = 'hh tt';
1491+
fixture.componentInstance.customDate = new Date(2018, 10, 27, 17, 45, 0, 0);
1492+
fixture.detectChanges();
1493+
1494+
const clearTime = dom.queryAll(By.css('.igx-icon'))[1];
1495+
1496+
UIInteractions.clickElement(clearTime);
1497+
fixture.detectChanges();
1498+
input.nativeElement.dispatchEvent(new Event('focus'));
1499+
fixture.detectChanges();
1500+
1501+
input.nativeElement.dispatchEvent(new Event('blur'));
1502+
fixture.detectChanges();
1503+
1504+
expect(input.nativeElement.value).toEqual('');
1505+
expect(input.nativeElement.placeholder).toEqual('hh tt');
1506+
1507+
input.nativeElement.dispatchEvent(new Event('focus'));
1508+
fixture.detectChanges();
1509+
1510+
expect(input.nativeElement.value).toBe('-- AM');
1511+
}));
1512+
1513+
it('Should navigate dropdown lists correctly when format conatains only hours.', fakeAsync(() => {
1514+
fixture.componentInstance.format = 'hh tt';
1515+
fixture.componentInstance.customDate = new Date(2018, 10, 27, 17, 45, 0, 0);
1516+
fixture.detectChanges();
1517+
1518+
const iconTime = dom.queryAll(By.css('.igx-icon'))[0];
1519+
1520+
UIInteractions.clickElement(iconTime);
1521+
tick();
1522+
fixture.detectChanges();
1523+
1524+
dom.query(By.css('.igx-time-picker__hourList')).nativeElement.focus();
1525+
fixture.detectChanges();
1526+
1527+
expect(document.activeElement.classList).toContain('igx-time-picker__hourList');
1528+
1529+
document.activeElement.dispatchEvent(new KeyboardEvent('keydown', { key: 'ArrowRight', bubbles: true }));
1530+
fixture.detectChanges();
1531+
1532+
expect(document.activeElement.classList).toContain('igx-time-picker__ampmList');
1533+
1534+
document.activeElement.dispatchEvent(new KeyboardEvent('keydown', { key: 'ArrowLeft', bubbles: true }));
1535+
document.activeElement.dispatchEvent(new KeyboardEvent('keydown', { key: 'ArrowUp', bubbles: true }));
1536+
document.activeElement.dispatchEvent(new KeyboardEvent('keydown', { key: 'Enter', bubbles: true }));
1537+
tick();
1538+
fixture.detectChanges();
1539+
1540+
expect(input.nativeElement.value).toEqual('04 PM');
1541+
expect(timePicker.value).toEqual(new Date(2018, 10, 27, 16, 45, 0, 0));
1542+
}));
1543+
1544+
it('Should navigate dropdown lists correctly when format conatains only minutes.', fakeAsync(() => {
1545+
fixture.componentInstance.format = 'mm tt';
1546+
fixture.componentInstance.customDate = new Date(2018, 10, 27, 17, 45, 0, 0);
1547+
fixture.detectChanges();
1548+
1549+
const iconTime = dom.queryAll(By.css('.igx-icon'))[0];
1550+
1551+
UIInteractions.clickElement(iconTime);
1552+
tick();
1553+
fixture.detectChanges();
1554+
1555+
dom.query(By.css('.igx-time-picker__minuteList')).nativeElement.focus();
1556+
fixture.detectChanges();
1557+
1558+
expect(document.activeElement.classList).toContain('igx-time-picker__minuteList');
1559+
1560+
document.activeElement.dispatchEvent(new KeyboardEvent('keydown', { key: 'ArrowRight', bubbles: true }));
1561+
fixture.detectChanges();
1562+
1563+
expect(document.activeElement.classList).toContain('igx-time-picker__ampmList');
1564+
1565+
document.activeElement.dispatchEvent(new KeyboardEvent('keydown', { key: 'ArrowLeft', bubbles: true }));
1566+
document.activeElement.dispatchEvent(new KeyboardEvent('keydown', { key: 'ArrowDown', bubbles: true }));
1567+
document.activeElement.dispatchEvent(new KeyboardEvent('keydown', { key: 'Enter', bubbles: true }));
1568+
tick();
1569+
fixture.detectChanges();
1570+
1571+
expect(input.nativeElement.value).toEqual('46 PM');
1572+
expect(timePicker.value).toEqual(new Date(2018, 10, 27, 17, 46, 0, 0));
1573+
}));
1574+
1575+
it('Should spin editable input correctly when format conatains only hours - 24 hour format.', fakeAsync(() => {
1576+
fixture.componentInstance.format = 'HH';
1577+
fixture.componentInstance.customDate = new Date(2018, 10, 27, 17, 45, 0, 0);
1578+
fixture.detectChanges();
1579+
1580+
expect(input.nativeElement.value).toBe('17');
1581+
1582+
input.nativeElement.focus();
1583+
input.nativeElement.setSelectionRange(0, 0);
1584+
fixture.detectChanges();
1585+
1586+
UIInteractions.triggerKeyDownEvtUponElem('ArrowUp', input.nativeElement, true);
1587+
fixture.detectChanges();
1588+
1589+
expect(input.nativeElement.value).toBe('18');
1590+
expect(timePicker.value).toEqual(new Date(2018, 10, 27, 18, 45, 0, 0));
1591+
}));
1592+
1593+
it('Should spin editable input correctly when format conatains only minutes.', fakeAsync(() => {
1594+
fixture.componentInstance.format = 'mm tt';
1595+
fixture.componentInstance.customDate = new Date(2018, 10, 27, 17, 45, 0, 0);
1596+
fixture.detectChanges();
1597+
1598+
expect(input.nativeElement.value).toBe('45 PM');
1599+
1600+
input.nativeElement.setSelectionRange(0, 0);
1601+
tick();
1602+
fixture.detectChanges();
1603+
1604+
UIInteractions.triggerKeyDownEvtUponElem('ArrowUp', input.nativeElement, true);
1605+
fixture.detectChanges();
1606+
1607+
expect(input.nativeElement.value).toBe('46 PM');
1608+
expect(timePicker.value).toEqual(new Date(2018, 10, 27, 17, 46, 0, 0));
1609+
}));
1610+
1611+
it('Should spin editable input AM/PM correctly when format conatains only hours.', fakeAsync(() => {
1612+
fixture.componentInstance.format = 'hh tt';
1613+
fixture.componentInstance.customDate = new Date(2018, 10, 27, 17, 45, 0, 0);
1614+
fixture.detectChanges();
1615+
1616+
expect(input.nativeElement.value).toBe('05 PM');
1617+
1618+
input.nativeElement.setSelectionRange(3, 3);
1619+
fixture.detectChanges();
1620+
1621+
UIInteractions.triggerKeyDownEvtUponElem('ArrowDown', input.nativeElement, true);
1622+
fixture.detectChanges();
1623+
1624+
expect(input.nativeElement.value).toBe('05 AM');
1625+
expect(timePicker.value).toEqual(new Date(2018, 10, 27, 5, 45, 0, 0));
1626+
}));
1627+
1628+
it('Should render dialog and input group correctly when format conatains only minutes.', fakeAsync(() => {
1629+
fixture.componentInstance.format = 'mm';
1630+
fixture.componentInstance.mode = InteractionMode.Dialog;
1631+
fixture.detectChanges();
1632+
1633+
input = dom.query(By.directive(IgxInputDirective));
1634+
UIInteractions.clickElement(input);
1635+
fixture.detectChanges();
1636+
1637+
const hourColumn = dom.query(By.css('.igx-time-picker__hourList'));
1638+
const minuteColumn = dom.query(By.css('.igx-time-picker__minuteList'));
1639+
const ampmColumn = dom.query(By.css('.igx-time-picker__ampmList'));
1640+
1641+
expect(hourColumn).toBeNull();
1642+
expect(ampmColumn).toBeNull();
1643+
expect(minuteColumn).not.toBeNull();
1644+
1645+
expect(input.nativeElement.value).toEqual('05');
1646+
expect(timePicker.mask).toEqual('00');
1647+
expect(timePicker.value).toEqual(fixture.componentInstance.customDate);
1648+
1649+
const headerHour = dom.query(By.css('.igx-time-picker__header-hour'));
1650+
const headerAmPm = dom.query(By.css('.igx-time-picker__header-ampm'));
1651+
1652+
expect(headerHour.nativeElement.innerText.replace(/\n/g, '')).toEqual('4:05');
1653+
expect(headerAmPm.nativeElement.innerText).toEqual('');
1654+
}));
1655+
1656+
it('Should render dialog and input group correctly when format conatains only hours.', fakeAsync(() => {
1657+
fixture.componentInstance.format = 'hh tt';
1658+
fixture.componentInstance.mode = InteractionMode.Dialog;
1659+
fixture.detectChanges();
1660+
1661+
input = dom.query(By.directive(IgxInputDirective));
1662+
UIInteractions.clickElement(input);
1663+
tick();
1664+
fixture.detectChanges();
1665+
1666+
const hourColumn = dom.query(By.css('.igx-time-picker__hourList'));
1667+
const minuteColumn = dom.query(By.css('.igx-time-picker__minuteList'));
1668+
const ampmColumn = dom.query(By.css('.igx-time-picker__ampmList'));
1669+
1670+
expect(hourColumn).not.toBeNull();
1671+
expect(ampmColumn).not.toBeNull();
1672+
expect(minuteColumn).toBeNull();
1673+
1674+
expect(input.nativeElement.value).toEqual('04 AM');
1675+
expect(timePicker.mask).toEqual('00 LL');
1676+
expect(timePicker.value).toEqual(fixture.componentInstance.customDate);
1677+
1678+
const headerHour = dom.query(By.css('.igx-time-picker__header-hour'));
1679+
const headerAmPm = dom.query(By.css('.igx-time-picker__header-ampm'));
1680+
1681+
expect(headerHour.nativeElement.innerText.replace(/\n/g, '')).toEqual('04:5');
1682+
expect(headerAmPm.nativeElement.innerText).toEqual('AM');
1683+
}));
1684+
});
14491685
});
14501686

14511687
@Component({
@@ -1579,13 +1815,14 @@ export class IgxTimePickerDropDownComponent {
15791815
<igx-time-picker
15801816
[value]="customDate"
15811817
[mode]="mode"
1582-
[format]="'H:m'">
1818+
[format]="format">
15831819
</igx-time-picker>
15841820
`
15851821
})
15861822
export class IgxTimePickerDropDownSingleHourComponent {
15871823
customDate = new Date(2018, 10, 27, 4, 5);
15881824
mode = InteractionMode.DropDown;
1825+
format = 'H:m';
15891826

15901827
@ViewChild(IgxTimePickerComponent) public timePicker: IgxTimePickerComponent;
15911828
}

0 commit comments

Comments
 (0)