Skip to content

Commit f645ffb

Browse files
committed
feat(DlDateAdapterString): add support for string date in model
Also updated docs and simplified release configuration in package.json Fixes #412
1 parent fa18b9e commit f645ffb

6 files changed

+276
-3
lines changed
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,72 @@
1+
import {DlDateAdapter} from './dl-date-adapter';
2+
import * as _moment from 'moment';
3+
import {Inject, InjectionToken} from '@angular/core';
4+
5+
/**
6+
* Work around for moment namespace conflict when used with webpack and rollup.
7+
* See https://github.com/dherges/ng-packagr/issues/163
8+
*
9+
* Depending on whether rollup is used, moment needs to be imported differently.
10+
* Since Moment.js doesn't have a default export, we normally need to import using
11+
* the `* as`syntax.
12+
*
13+
* rollup creates a synthetic default module and we thus need to import it using
14+
* the `default as` syntax.
15+
*
16+
* @internal
17+
*
18+
**/
19+
const moment = _moment;
20+
21+
22+
/**
23+
* InjectionToken for string dates that can be used to override default output format.
24+
**/
25+
export const DL_STRING_DATE_OUTPUT_FORMAT = new InjectionToken<string>('DL_STRING_DATE_OUTPUT_FORMAT');
26+
27+
/**
28+
* InjectionToken for string dates that can be used to override default input formats.
29+
**/
30+
export const DL_STRING_DATE_INPUT_FORMATS = new InjectionToken<string[]>('DL_STRING_DATE_INPUT_FORMATS');
31+
32+
/**
33+
* Adapts `string` to be usable as a date by date/time components that work with dates.
34+
**/
35+
export class DlDateAdapterString extends DlDateAdapter<string> {
36+
37+
private readonly modelFormat: string;
38+
private readonly inputFormats: string[];
39+
40+
constructor(@Inject(DL_STRING_DATE_INPUT_FORMATS) inputFormats: string[],
41+
@Inject(DL_STRING_DATE_OUTPUT_FORMAT) modelFormat: string) {
42+
super();
43+
this.inputFormats = inputFormats;
44+
this.modelFormat = modelFormat;
45+
}
46+
47+
/**
48+
* Returns the specified number.
49+
* @param milliseconds
50+
* a moment time time.
51+
* @returns
52+
* the specified moment in time.
53+
*/
54+
fromMilliseconds(milliseconds: number): string {
55+
return moment(milliseconds).format(this.modelFormat);
56+
}
57+
58+
/**
59+
* Returns the specified number.
60+
* @param value
61+
* a moment time time or `null`
62+
* @returns
63+
* the milliseconds for the specified value or `null`
64+
* `null` is returned when value is not a valid input date string
65+
*/
66+
toMilliseconds(value: string | null): number | null {
67+
if (value !== undefined && value !== null) {
68+
const newMoment = moment(value, this.inputFormats, true);
69+
return newMoment.isValid() ? newMoment.valueOf() : undefined;
70+
}
71+
}
72+
}

src/lib/dl-date-time-picker/dl-date-time-picker.component.md

+29-2
Original file line numberDiff line numberDiff line change
@@ -15,17 +15,44 @@ The following keyboard shortcuts are supported in in all views:
1515
| `PAGE_DOWN` | Go to the same cell in the next time period |
1616
| `ENTER` or `SPACE` | Select current cell |
1717

18-
## Date Adapter
18+
## Supported date types
19+
20+
Import the module corresponding to the desired data type of the date in the model.
21+
* Native JavaScript Date: import 'DlDateTimePickerDateModule'
22+
* Moment Date: import 'DlDateTimePickerMomentModule'
23+
* Milliseconds (local): import 'DlDateTimePickerNumberModule'
24+
* String (local): import 'DlDateTimePickerStringModule'
1925

2026
A `DateAdapter` is used to adapt the data type in the model to the `number` data type
2127
used internally by the date/time picker.
22-
28+
2329
If you need a different data type than what is currently supported, you can extend
2430
`DlDateAdapter<D>` to provide the data type you need then override the `DlDateAdapter`
2531
provider in `app.module.ts` to use your new class.
2632

2733
`providers: [{provide: DlDateAdapter, useClass: MyCustomDateAdapter}],`
2834

35+
### String Date Adapter Formats
36+
The input and output formats for dates are injected into the `DlDateAdapterString` class
37+
using the `DL_STRING_DATE_INPUT_FORMATS` and `DL_STRING_DATE_OUTPUT_FORMAT` tokens.
38+
39+
`DL_STRING_DATE_OUTPUT_FORMAT` defaults to `moment`'s `lll` long date format.
40+
41+
`DL_STRING_DATE_INPUT_FORMATS` defaults to the following:
42+
```typescript
43+
[
44+
moment.localeData().longDateFormat('lll'),
45+
'YYYY-MM-DDTHH:mm',
46+
'YYYY-MM-DDTHH:mm:ss',
47+
'YYYY-MM-DDTHH:mm:ss.SSS',
48+
'YYYY-MM-DD',
49+
'YYYY-MM-DDTHH:mm:ss.SSS[Z]' // ISO_8601
50+
]
51+
```
52+
53+
If you want different formats, override the injection tokens in `app.module.ts`
54+
i.e `{provide: DL_STRING_DATE_OUTPUT_FORMAT, useValue: '<what ever format you want goes here>'}`
55+
2956
## Model Provider
3057

3158
`ModelProvider`s are used to create the `Model` for each of the `views` in the date/time picker.

src/lib/dl-date-time-picker/dl-date-time-picker.component.ts

+1-1
Original file line numberDiff line numberDiff line change
@@ -455,7 +455,7 @@ export class DlDateTimePickerComponent<D> implements OnChanges, OnInit, ControlV
455455
**/
456456
private getStartDate() {
457457
if (hasValue(this._value)) {
458-
return this._value;
458+
return this._dateAdapter.toMilliseconds(this._value);
459459
}
460460
if (hasValue(this.startDate)) {
461461
return this.startDate;

src/lib/dl-date-time-picker/dl-date-time-picker.module.ts

+44
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,25 @@ import {DlMonthModelProvider} from './dl-model-provider-month';
1919
import {DlDayModelProvider} from './dl-model-provider-day';
2020
import {DlHourModelProvider} from './dl-model-provider-hour';
2121
import {DlMinuteModelProvider} from './dl-model-provider-minute';
22+
import {DL_STRING_DATE_INPUT_FORMATS, DL_STRING_DATE_OUTPUT_FORMAT, DlDateAdapterString} from './dl-date-adapter-string';
23+
24+
import * as _moment from 'moment';
25+
26+
/**
27+
* Work around for moment namespace conflict when used with webpack and rollup.
28+
* See https://github.com/dherges/ng-packagr/issues/163
29+
*
30+
* Depending on whether rollup is used, moment needs to be imported differently.
31+
* Since Moment.js doesn't have a default export, we normally need to import using
32+
* the `* as`syntax.
33+
*
34+
* rollup creates a synthetic default module and we thus need to import it using
35+
* the `default as` syntax.
36+
*
37+
* @internal
38+
*
39+
**/
40+
const moment = _moment;
2241

2342
/**
2443
* Import this module to supply your own `DateAdapter` provider.
@@ -72,3 +91,28 @@ export class DlDateTimePickerDateModule {
7291
})
7392
export class DlDateTimePickerMomentModule {
7493
}
94+
95+
/**
96+
* Import this module to store a `string` in the model.
97+
*/
98+
@NgModule({
99+
imports: [DlDateTimePickerModule],
100+
exports: [DlDateTimePickerComponent],
101+
providers: [
102+
{
103+
provide: DL_STRING_DATE_INPUT_FORMATS, useValue: [
104+
moment.localeData().longDateFormat('lll'),
105+
'YYYY-MM-DDTHH:mm',
106+
'YYYY-MM-DDTHH:mm:ss',
107+
'YYYY-MM-DDTHH:mm:ss.SSS',
108+
'YYYY-MM-DD',
109+
moment.ISO_8601
110+
]
111+
},
112+
{provide: DL_STRING_DATE_OUTPUT_FORMAT, useValue: moment.localeData().longDateFormat('lll')},
113+
{provide: DlDateAdapter, useClass: DlDateAdapterString}
114+
],
115+
})
116+
export class DlDateTimePickerStringModule {
117+
}
118+
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,68 @@
1+
import {DlDateAdapterString} from '../../dl-date-adapter-string';
2+
import {DlDateAdapter} from '../../dl-date-adapter';
3+
4+
import * as _moment from 'moment';
5+
import {Moment} from 'moment';
6+
7+
/**
8+
* Work around for moment namespace conflict when used with webpack and rollup.
9+
* See https://github.com/dherges/ng-packagr/issues/163
10+
*
11+
* Depending on whether rollup is used, moment needs to be imported differently.
12+
* Since Moment.js doesn't have a default export, we normally need to import using
13+
* the `* as`syntax.
14+
*
15+
* rollup creates a synthetic default module and we thus need to import it using
16+
* the `default as` syntax.
17+
*
18+
* @internal
19+
*
20+
**/
21+
const moment = _moment;
22+
23+
/**
24+
* @license
25+
* Copyright 2013-present Dale Lotts All Rights Reserved.
26+
* http://www.dalelotts.com
27+
*
28+
* Use of this source code is governed by an MIT-style license that can be
29+
* found in the LICENSE file at https://github.com/dalelotts/angular-bootstrap-datetimepicker/blob/master/LICENSE
30+
*/
31+
32+
33+
34+
describe('DlDateAdapterString', () => {
35+
36+
describe('default configuration', () => {
37+
let dateAdapter: DlDateAdapterString;
38+
let testMoment: Moment;
39+
beforeEach(() => {
40+
testMoment = moment(1523077200000);
41+
dateAdapter = new DlDateAdapterString([
42+
moment.localeData().longDateFormat('lll'),
43+
'YYYY-MM-DDTHH:mm',
44+
'YYYY-MM-DDTHH:mm:ss',
45+
'YYYY-MM-DDTHH:mm:ss.SSS',
46+
'YYYY-MM-DD',
47+
'YYYY-MM-DDTHH:mm:ss.SSS[Z]' // ISO_8601
48+
],
49+
moment.localeData().longDateFormat('lll')
50+
);
51+
});
52+
53+
describe('fromMilliseconds', () => {
54+
it('should return "lll" moment format', () => {
55+
expect(dateAdapter.fromMilliseconds(1523077200000)).toEqual(testMoment.format('lll'));
56+
});
57+
});
58+
59+
describe('toMilliseconds', () => {
60+
it('should accept "lll" moment format', () => {
61+
expect(dateAdapter.toMilliseconds(testMoment.format('lll'))).toEqual(1523077200000);
62+
});
63+
it('should return undefined for invalid date value', () => {
64+
expect(dateAdapter.toMilliseconds('Aor 7, 2018 12:00 AM')).toBeUndefined();
65+
});
66+
});
67+
});
68+
});
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,62 @@
1+
/**
2+
* @license
3+
* Copyright 2013-present Dale Lotts All Rights Reserved.
4+
* http://www.dalelotts.com
5+
*
6+
* Use of this source code is governed by an MIT-style license that can be
7+
* found in the LICENSE file at https://github.com/dalelotts/angular-bootstrap-datetimepicker/blob/master/LICENSE
8+
*/
9+
10+
import {DlDateTimePickerComponent} from '../../dl-date-time-picker.component';
11+
import {Component, DebugElement, ViewChild} from '@angular/core';
12+
import {async, ComponentFixture, TestBed} from '@angular/core/testing';
13+
import {By} from '@angular/platform-browser';
14+
import {DlDateTimePickerStringModule} from '../../index';
15+
16+
17+
@Component({
18+
template: '<dl-date-time-picker minView="day"></dl-date-time-picker>'
19+
})
20+
class ModelTypeComponent {
21+
@ViewChild(DlDateTimePickerComponent) picker: DlDateTimePickerComponent<string>;
22+
}
23+
24+
describe('DlDateTimePickerComponent modelType', () => {
25+
26+
beforeEach(async(() => {
27+
return TestBed.configureTestingModule({
28+
imports: [
29+
DlDateTimePickerStringModule
30+
],
31+
declarations: [
32+
ModelTypeComponent,
33+
]
34+
})
35+
.compileComponents();
36+
}));
37+
38+
describe('string formatted Date', () => {
39+
let component: ModelTypeComponent;
40+
let fixture: ComponentFixture<ModelTypeComponent>;
41+
let debugElement: DebugElement;
42+
let nativeElement: any;
43+
44+
beforeEach(async(() => {
45+
fixture = TestBed.createComponent(ModelTypeComponent);
46+
fixture.detectChanges();
47+
fixture.whenStable().then(() => {
48+
fixture.detectChanges();
49+
component = fixture.componentInstance;
50+
debugElement = fixture.debugElement;
51+
nativeElement = debugElement.nativeElement;
52+
});
53+
}));
54+
55+
it('should be string type', () => {
56+
const nowElement = fixture.debugElement.query(By.css('.dl-abdtp-now'));
57+
nowElement.nativeElement.click();
58+
59+
expect(component.picker.value).toEqual(jasmine.any(String));
60+
});
61+
});
62+
});

0 commit comments

Comments
 (0)