Skip to content

Commit

Permalink
feat(datepicker): allow parsing and formatting dates in a custom way
Browse files Browse the repository at this point in the history
Closes #755
  • Loading branch information
jnizet authored and pkozlowski-opensource committed Sep 17, 2016
1 parent 64eca2d commit 401fcfa
Show file tree
Hide file tree
Showing 6 changed files with 35 additions and 15 deletions.
1 change: 1 addition & 0 deletions demo/src/app/components/datepicker/datepicker.component.ts
Expand Up @@ -10,6 +10,7 @@ import {DEMO_SNIPPETS} from './demos';
<ngbd-api-docs-class type="NgbDateStruct"></ngbd-api-docs-class>
<ngbd-api-docs-class type="DayTemplateContext"></ngbd-api-docs-class>
<ngbd-api-docs-class type="NgbDatepickerI18n"></ngbd-api-docs-class>
<ngbd-api-docs-class type="NgbDateParserFormatter"></ngbd-api-docs-class>
<ngbd-api-docs-config type="NgbDatepickerConfig"></ngbd-api-docs-config>
<ngbd-example-box demoTitle="Basic datepicker" [htmlSnippet]="snippets.basic.markup" [tsSnippet]="snippets.basic.code">
<ngbd-datepicker-basic></ngbd-datepicker-basic>
Expand Down
2 changes: 1 addition & 1 deletion src/datepicker/datepicker-input.ts
Expand Up @@ -133,7 +133,7 @@ export class NgbInputDatepicker implements ControlValueAccessor {
* @internal
*/
manualDateChange(value: string) {
this._model = this._parserFormatter.parse(value);
this._model = NgbDate.from(this._parserFormatter.parse(value));
this._onChange(this._model ? {year: this._model.year, month: this._model.month, day: this._model.day} : null);
this._writeModelValue(this._model);
}
Expand Down
1 change: 1 addition & 0 deletions src/datepicker/datepicker.module.ts
Expand Up @@ -16,6 +16,7 @@ import {NgbDatepickerConfig} from './datepicker-config';
export {NgbDatepickerConfig} from './datepicker-config';
export {NgbDatepickerI18n} from './datepicker-i18n';
export {NgbDateStruct} from './ngb-date-struct';
export {NgbDateParserFormatter} from './ngb-date-parser-formatter';

@NgModule({
declarations: [
Expand Down
12 changes: 6 additions & 6 deletions src/datepicker/ngb-date-parser-formatter.spec.ts
Expand Up @@ -15,7 +15,7 @@ describe('ngb-date parsing and formatting', () => {
expect(pf.parse(' ')).toBeNull();
});

it('should parse valid date', () => { expect(pf.parse('2016-05-12')).toEqual(new NgbDate(2016, 4, 12)); });
it('should parse valid date', () => { expect(pf.parse('2016-05-12')).toEqual({year: 2016, month: 4, day: 12}); });

it('should parse non-date as null', () => {
expect(pf.parse('foo-bar-baz')).toBeNull();
Expand All @@ -24,7 +24,7 @@ describe('ngb-date parsing and formatting', () => {
});

it('should do its best parsing incomplete dates',
() => { expect(pf.parse('2011-5')).toEqual(new NgbDate(2011, 4, null)); });
() => { expect(pf.parse('2011-5')).toEqual({year: 2011, month: 4, day: null}); });
});

describe('formatting', () => {
Expand All @@ -34,14 +34,14 @@ describe('ngb-date parsing and formatting', () => {
expect(pf.format(undefined)).toBe('');
});

it('should format a valid date', () => { expect(pf.format(new NgbDate(2016, 9, 15))).toBe('2016-10-15'); });
it('should format a valid date', () => { expect(pf.format({year: 2016, month: 9, day: 15})).toBe('2016-10-15'); });

it('should format a valid date with padding',
() => { expect(pf.format(new NgbDate(2016, 9, 5))).toBe('2016-10-05'); });
() => { expect(pf.format({year: 2016, month: 9, day: 5})).toBe('2016-10-05'); });

it('should try its best with invalid dates', () => {
expect(pf.format(new NgbDate(2016, NaN, undefined))).toBe('2016--');
expect(pf.format(new NgbDate(2016, null, 0))).toBe('2016--00');
expect(pf.format({year: 2016, month: NaN, day: undefined})).toBe('2016--');
expect(pf.format({year: 2016, month: null, day: 0})).toBe('2016--00');
});
});

Expand Down
31 changes: 24 additions & 7 deletions src/datepicker/ngb-date-parser-formatter.ts
@@ -1,27 +1,44 @@
import {NgbDate} from './ngb-date';
import {padNumber, toInteger, isNumber} from '../util/util';
import {NgbDateStruct} from './ngb-date-struct';

/**
* Abstract type serving as a DI token for the service parsing and formatting dates for the NgbInputDatepicker
* directive. A default implementation using the ISO format is provided, but you can provide another implementation
* to use an alternative format.
*/
export abstract class NgbDateParserFormatter {
abstract parse(value: string): NgbDate;
abstract format(date: NgbDate): string;
/**
* Parses the given value to an NgbDateStruct. Implementations should try their best to provide a result, even
* partial. They must return null if the value can't be parsed.
* @param value the value to parse
*/
abstract parse(value: string): NgbDateStruct;

/**
* Formats the given date to a string. Implementations should return an empty string if the given date is null,
* and try their best to provide a partial result if the given date is incomplete or invalid.
* @param date the date to format as a string
*/
abstract format(date: NgbDateStruct): string;
}

export class NgbDateISOParserFormatter extends NgbDateParserFormatter {
parse(value: string): NgbDate {
parse(value: string): NgbDateStruct {
if (value) {
const dateParts = value.trim().split('-');
if (dateParts.length === 1 && isNumber(dateParts[0])) {
return new NgbDate(toInteger(dateParts[0]), null, null);
return {year: toInteger(dateParts[0]), month: null, day: null};
} else if (dateParts.length === 2 && isNumber(dateParts[0]) && isNumber(dateParts[1])) {
return new NgbDate(toInteger(dateParts[0]), toInteger(dateParts[1]) - 1, null);
return {year: toInteger(dateParts[0]), month: toInteger(dateParts[1]) - 1, day: null};
} else if (dateParts.length === 3 && isNumber(dateParts[0]) && isNumber(dateParts[1]) && isNumber(dateParts[2])) {
return new NgbDate(toInteger(dateParts[0]), toInteger(dateParts[1]) - 1, toInteger(dateParts[2]));
return {year: toInteger(dateParts[0]), month: toInteger(dateParts[1]) - 1, day: toInteger(dateParts[2])};
}
}
return null;
}

format(date: NgbDate): string {
format(date: NgbDateStruct): string {
return date ?
`${date.year}-${isNumber(date.month) ? padNumber(date.month + 1) : ''}-${isNumber(date.day) ? padNumber(date.day) : ''}` :
'';
Expand Down
3 changes: 2 additions & 1 deletion src/index.ts
Expand Up @@ -26,7 +26,8 @@ export {
NgbDatepickerModule,
NgbDatepickerI18n,
NgbDatepickerConfig,
NgbDateStruct
NgbDateStruct,
NgbDateParserFormatter
} from './datepicker/datepicker.module';
export {NgbDropdownModule, NgbDropdownConfig} from './dropdown/dropdown.module';
export {NgbModalModule, NgbModal, NgbModalOptions, NgbModalRef, ModalDismissReasons} from './modal/modal.module';
Expand Down

0 comments on commit 401fcfa

Please sign in to comment.