-
Notifications
You must be signed in to change notification settings - Fork 18
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Add support for timezone / local dates (#26)
* Add DateLocalValueAccessor with timezone support See: #13 * Add DateLocalValueAccessor with timezone support: use valueAsDate Assign UTC Date to valueAsDate Output Local Date See: #13 * Create dedicated LocalDateValueAccessorModule, UTs See: #13 * DateValueAccessor UT: check if date is in UTC time See: #13 * LocalDateValueAccessor: Update UTs See: #13 * LocalDateValueAccessor: public API See: #13 * Add DateLocalValueAccessor with timezone support: use valueAsDate Assign UTC Date to valueAsDate Output Local Date See: #13 * Update Demo See: #13 * Update Demo: Fix typo See: #13 * Update README
- Loading branch information
Showing
12 changed files
with
252 additions
and
22 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
7 changes: 7 additions & 0 deletions
7
workspace/projects/date-value-accessor/src/lib/local-date-value-accessor.module.ts
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,7 @@ | ||
import { NgModule } from '@angular/core'; | ||
import { LocalDateValueAccessor } from './local-date-value-accessor'; | ||
@NgModule({ | ||
declarations: [LocalDateValueAccessor], | ||
exports: [LocalDateValueAccessor] | ||
}) | ||
export class LocalDateValueAccessorModule { } |
61 changes: 61 additions & 0 deletions
61
workspace/projects/date-value-accessor/src/lib/local-date-value-accessor.spec.ts
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,61 @@ | ||
import { Component, DebugElement } from '@angular/core'; | ||
import { ComponentFixture, TestBed, waitForAsync } from '@angular/core/testing'; | ||
import { FormsModule } from '@angular/forms'; | ||
import { By } from '@angular/platform-browser'; | ||
|
||
import { dispatchInputEvent } from './spec-utils'; | ||
import { LocalDateValueAccessor } from './local-date-value-accessor'; | ||
|
||
@Component({ | ||
template: ` | ||
<form> | ||
<input type="date" name="fixedInput" [(ngModel)]="testDate" useValueAsLocalDate> | ||
</form>` | ||
}) | ||
export class TestFormComponent { | ||
testDate: Date = new Date(2020, 11, 8); // Create LOCAL Date | ||
} | ||
|
||
describe('LocalDateValueAccessor', () => { | ||
|
||
let fixture: ComponentFixture<TestFormComponent>; | ||
|
||
beforeEach(waitForAsync(() => { | ||
TestBed.configureTestingModule({ | ||
declarations: [TestFormComponent, LocalDateValueAccessor], | ||
imports: [FormsModule] | ||
}) | ||
.compileComponents(); | ||
})); | ||
|
||
beforeEach(() => { | ||
fixture = TestBed.createComponent(TestFormComponent); | ||
}); | ||
|
||
beforeEach(waitForAsync(() => { | ||
// https://stackoverflow.com/questions/39582707/updating-input-html-field-from-within-an-angular-2-test | ||
fixture.detectChanges(); | ||
fixture.whenStable(); | ||
})); | ||
|
||
describe('with the "useValueAsDateLocal" attribute', () => { | ||
|
||
let fixedInput: DebugElement; | ||
beforeEach(() => fixedInput = fixture.debugElement.query(By.css('input[name=fixedInput]'))); | ||
|
||
it('should fix date input controls to bind on dates', waitForAsync(() => { | ||
expect(fixedInput.nativeElement.value).toBe('2020-12-08'); | ||
})); | ||
|
||
it('should populate LOCAL dates (instead of strings) on change', waitForAsync(() => { | ||
dispatchInputEvent(fixedInput.nativeElement, '2020-12-31'); | ||
expect(fixture.componentInstance.testDate).toEqual(jasmine.any(Date)); | ||
expect(fixture.componentInstance.testDate).toEqual(new Date(2020, 11, 31)); | ||
expect(fixture.componentInstance.testDate.getDate()).toBe(31); | ||
expect(fixture.componentInstance.testDate.getMonth()).toBe(11); | ||
expect(fixture.componentInstance.testDate.getFullYear()).toBe(2020); | ||
expect(fixture.componentInstance.testDate.getHours()).toBe(0); | ||
expect(fixture.componentInstance.testDate.getMinutes()).toBe(0); | ||
})); | ||
}); | ||
}); |
54 changes: 54 additions & 0 deletions
54
workspace/projects/date-value-accessor/src/lib/local-date-value-accessor.ts
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,54 @@ | ||
import { Directive, ElementRef, HostListener, Renderer2, forwardRef } from '@angular/core'; | ||
import { ControlValueAccessor, NG_VALUE_ACCESSOR } from '@angular/forms'; | ||
|
||
export const LOCAL_DATE_VALUE_ACCESSOR: any = { | ||
provide: NG_VALUE_ACCESSOR, | ||
useExisting: forwardRef(() => LocalDateValueAccessor), | ||
multi: true | ||
}; | ||
|
||
/** | ||
* The accessor for writing a value and listening to changes on a date input element | ||
* | ||
* ### Example | ||
* `<input type="date" name="myBirthday" ngModel useValueAsLocalDate>` | ||
*/ | ||
@Directive({ | ||
selector: '[useValueAsLocalDate]', | ||
providers: [LOCAL_DATE_VALUE_ACCESSOR] | ||
}) | ||
// tslint:disable-next-line: directive-class-suffix | ||
export class LocalDateValueAccessor implements ControlValueAccessor { | ||
|
||
onChange: any = () => {}; | ||
|
||
@HostListener('input', ['$event.target.valueAsDate']) onInput = (date: Date) => { | ||
let selectedDate: Date | null = null; | ||
if (date) { | ||
// Create LOCAL Date, time is set to 00:00 in LOCAL time | ||
selectedDate = new Date(date.getUTCFullYear(), date.getUTCMonth(), date.getUTCDate());; | ||
} | ||
this.onChange(selectedDate); | ||
} | ||
@HostListener('blur', []) onTouched = () => { }; | ||
|
||
constructor(private renderer: Renderer2, private elementRef: ElementRef) { } | ||
|
||
writeValue(date: Date): void { | ||
// Create UTC Date, time is set to 00:00 in UTC time | ||
const utcDate: Date = date ? | ||
new Date(Date.UTC(date.getFullYear(), date.getMonth(), date.getDate())) : | ||
null; | ||
this.renderer.setProperty(this.elementRef.nativeElement, 'valueAsDate', utcDate); | ||
} | ||
|
||
registerOnChange(fn: (_: any) => void): void { this.onChange = fn; } | ||
registerOnTouched(fn: () => void): void { this.onTouched = fn; } | ||
|
||
setDisabledState(isDisabled: boolean): void { | ||
this.renderer.setProperty(this.elementRef.nativeElement, 'disabled', isDisabled); | ||
} | ||
} | ||
|
||
// Use Local Dates with html input type date | ||
// https://stackoverflow.com/questions/53032953/what-is-the-correct-way-to-set-and-get-htmlinputelement-valueasdate-using-local |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,4 @@ | ||
export function dispatchInputEvent(inputElement: HTMLInputElement, text: string): void { | ||
inputElement.value = text; | ||
inputElement.dispatchEvent(new Event('input')); | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.