mirror of
https://github.com/Alfresco/alfresco-ng2-components.git
synced 2025-06-30 18:15:11 +00:00
[ADF-2849] Search Date Range - Set the format of the date from config (#3288)
* format date chosen from the datePicker's calendar * format date on focusout event * fix tests & some code refactoring * more validation messages * unit tests * fix typecast error * move "dateFormat" to be part of the "date range" widget settings block * fix error on Moment "...Type 'moment.Moment' is not assignable to type 'moment.Moment'. Two different types with this name exist, but they are unrelated. Property 'isLocal' is missing in type 'Moment'..." * moment - use old version * change script - use recent version of moment
This commit is contained in:
parent
b66154773a
commit
5f004c9972
@ -145,7 +145,8 @@
|
|||||||
"component": {
|
"component": {
|
||||||
"selector": "date-range",
|
"selector": "date-range",
|
||||||
"settings": {
|
"settings": {
|
||||||
"field": "cm:created"
|
"field": "cm:created",
|
||||||
|
"dateFormat": "DD-MMM-YY"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
@ -188,7 +188,8 @@
|
|||||||
"VALIDATION": {
|
"VALIDATION": {
|
||||||
"REQUIRED-VALUE": "Required value",
|
"REQUIRED-VALUE": "Required value",
|
||||||
"NO-DAYS": "No days selected.",
|
"NO-DAYS": "No days selected.",
|
||||||
"INVALID-FORMAT": "Invalid Format"
|
"INVALID-FORMAT": "Invalid Format",
|
||||||
|
"BEYOND-MAX-DATE": "Date is too late."
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"ICONS": {
|
"ICONS": {
|
||||||
|
@ -3,22 +3,30 @@
|
|||||||
<input matInput [formControl]="from" [errorStateMatcher]="matcher"
|
<input matInput [formControl]="from" [errorStateMatcher]="matcher"
|
||||||
placeholder="{{ 'SEARCH.FILTER.RANGE.FROM-DATE' | translate }}"
|
placeholder="{{ 'SEARCH.FILTER.RANGE.FROM-DATE' | translate }}"
|
||||||
[matDatepicker]="fromDatepicker"
|
[matDatepicker]="fromDatepicker"
|
||||||
[max]="maxFrom">
|
[max]="maxFrom"
|
||||||
|
(focusout)="onChangedHandler($event, from)">
|
||||||
<mat-datepicker-toggle matSuffix [for]="fromDatepicker"></mat-datepicker-toggle>
|
<mat-datepicker-toggle matSuffix [for]="fromDatepicker"></mat-datepicker-toggle>
|
||||||
<mat-datepicker #fromDatepicker></mat-datepicker>
|
<mat-datepicker #fromDatepicker></mat-datepicker>
|
||||||
<mat-error *ngIf="from.hasError('required')">
|
<mat-error *ngIf="from.hasError('required')">
|
||||||
{{ 'SEARCH.FILTER.VALIDATION.REQUIRED-VALUE' | translate }}
|
{{ 'SEARCH.FILTER.VALIDATION.REQUIRED-VALUE' | translate }}
|
||||||
</mat-error>
|
</mat-error>
|
||||||
|
<mat-error *ngIf="from.hasError('matDatepickerMax')">
|
||||||
|
{{ 'SEARCH.FILTER.VALIDATION.BEYOND-MAX-DATE' | translate }}
|
||||||
|
</mat-error>
|
||||||
</mat-form-field>
|
</mat-form-field>
|
||||||
|
|
||||||
<mat-form-field>
|
<mat-form-field>
|
||||||
<input matInput [formControl]="to" [errorStateMatcher]="matcher"
|
<input matInput [formControl]="to" [errorStateMatcher]="matcher"
|
||||||
placeholder="{{ 'SEARCH.FILTER.RANGE.TO-DATE' | translate }}"
|
placeholder="{{ 'SEARCH.FILTER.RANGE.TO-DATE' | translate }}"
|
||||||
[matDatepicker]="toDatepicker"
|
[matDatepicker]="toDatepicker"
|
||||||
[min]="from.value">
|
[min]="from.value"
|
||||||
|
(focusout)="onChangedHandler($event, to)">
|
||||||
<mat-datepicker-toggle matSuffix [for]="toDatepicker"></mat-datepicker-toggle>
|
<mat-datepicker-toggle matSuffix [for]="toDatepicker"></mat-datepicker-toggle>
|
||||||
<mat-datepicker #toDatepicker></mat-datepicker>
|
<mat-datepicker #toDatepicker></mat-datepicker>
|
||||||
<mat-error *ngIf="!hasSelectedDays(from.value, to.value)">
|
<mat-error *ngIf="to.hasError('required')">
|
||||||
|
{{ 'SEARCH.FILTER.VALIDATION.REQUIRED-VALUE' | translate }}
|
||||||
|
</mat-error>
|
||||||
|
<mat-error *ngIf="to.hasError('matDatepickerMin')">
|
||||||
{{ 'SEARCH.FILTER.VALIDATION.NO-DAYS' | translate }}
|
{{ 'SEARCH.FILTER.VALIDATION.NO-DAYS' | translate }}
|
||||||
</mat-error>
|
</mat-error>
|
||||||
</mat-form-field>
|
</mat-form-field>
|
||||||
|
@ -15,26 +15,84 @@
|
|||||||
* limitations under the License.
|
* limitations under the License.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
import { SearchDateRangeComponent } from './search-date-range.component';
|
import { CustomMomentDateAdapter, SearchDateRangeComponent } from './search-date-range.component';
|
||||||
import moment from 'moment-es6';
|
import { Observable } from 'rxjs/Observable';
|
||||||
|
|
||||||
|
declare let moment: any;
|
||||||
|
|
||||||
describe('SearchDateRangeComponent', () => {
|
describe('SearchDateRangeComponent', () => {
|
||||||
|
|
||||||
let component: SearchDateRangeComponent;
|
let component: SearchDateRangeComponent;
|
||||||
let fromDate = '2016-10-16';
|
let fromDate = '2016-10-16';
|
||||||
let toDate = '2017-10-16';
|
let toDate = '2017-10-16';
|
||||||
|
const localeFixture = 'it';
|
||||||
|
const dateFormatFixture = 'DD-MMM-YY';
|
||||||
|
|
||||||
|
const buildAdapter = (): CustomMomentDateAdapter => {
|
||||||
|
const dateAdapter = new CustomMomentDateAdapter(null);
|
||||||
|
dateAdapter.customDateFormat = null;
|
||||||
|
return dateAdapter;
|
||||||
|
};
|
||||||
|
|
||||||
|
const buildUserPreferences = (): any => {
|
||||||
|
const userPreferences = {
|
||||||
|
userPreferenceStatus: { LOCALE: localeFixture },
|
||||||
|
select: (property) => {
|
||||||
|
return Observable.of(userPreferences.userPreferenceStatus[property]);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
return userPreferences;
|
||||||
|
};
|
||||||
|
|
||||||
|
const theDateAdapter = <any> buildAdapter();
|
||||||
|
|
||||||
beforeEach(() => {
|
beforeEach(() => {
|
||||||
component = new SearchDateRangeComponent();
|
component = new SearchDateRangeComponent(theDateAdapter, buildUserPreferences());
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should setup form elements on init', () => {
|
it('should setup form elements on init', () => {
|
||||||
component.ngOnInit();
|
component.ngOnInit();
|
||||||
expect(component.form).toBeDefined();
|
expect(component.from).toBeDefined();
|
||||||
expect(component.to).toBeDefined();
|
expect(component.to).toBeDefined();
|
||||||
expect(component.form).toBeDefined();
|
expect(component.form).toBeDefined();
|
||||||
});
|
});
|
||||||
|
|
||||||
|
it('should setup locale from userPreferencesService', () => {
|
||||||
|
spyOn(component, 'setLocale').and.stub();
|
||||||
|
component.ngOnInit();
|
||||||
|
expect(component.setLocale).toHaveBeenCalledWith(localeFixture);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should setup the format of the date from configuration', () => {
|
||||||
|
component.settings = { field: 'cm:created', dateFormat: dateFormatFixture };
|
||||||
|
component.ngOnInit();
|
||||||
|
expect(theDateAdapter.customDateFormat).toBe(dateFormatFixture);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should setup form control with formatted valid date on change', () => {
|
||||||
|
component.settings = { field: 'cm:created', dateFormat: dateFormatFixture };
|
||||||
|
component.ngOnInit();
|
||||||
|
|
||||||
|
const inputString = '20.feb.18';
|
||||||
|
const momentFromInput = moment(inputString, dateFormatFixture);
|
||||||
|
expect(momentFromInput.isValid()).toBeTruthy();
|
||||||
|
|
||||||
|
component.onChangedHandler({ srcElement: { value: inputString }}, component.from);
|
||||||
|
expect(component.from.value).toEqual(momentFromInput);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should NOT setup form control with invalid date on change', () => {
|
||||||
|
component.settings = { field: 'cm:created', dateFormat: dateFormatFixture };
|
||||||
|
component.ngOnInit();
|
||||||
|
|
||||||
|
const inputString = '20.f.18';
|
||||||
|
const momentFromInput = moment(inputString, dateFormatFixture);
|
||||||
|
expect(momentFromInput.isValid()).toBeFalsy();
|
||||||
|
|
||||||
|
component.onChangedHandler({ srcElement: { value: inputString }}, component.from);
|
||||||
|
expect(component.from.value).not.toEqual(momentFromInput);
|
||||||
|
});
|
||||||
|
|
||||||
it('should reset form', () => {
|
it('should reset form', () => {
|
||||||
component.ngOnInit();
|
component.ngOnInit();
|
||||||
component.form.setValue({ from: fromDate, to: toDate });
|
component.form.setValue({ from: fromDate, to: toDate });
|
||||||
|
@ -17,16 +17,44 @@
|
|||||||
|
|
||||||
import { OnInit, Component, ViewEncapsulation } from '@angular/core';
|
import { OnInit, Component, ViewEncapsulation } from '@angular/core';
|
||||||
import { FormControl, Validators, FormGroup } from '@angular/forms';
|
import { FormControl, Validators, FormGroup } from '@angular/forms';
|
||||||
|
import { DateAdapter, MAT_DATE_FORMATS, MAT_DATE_LOCALE } from '@angular/material/core';
|
||||||
|
import { MomentDateAdapter, MAT_MOMENT_DATE_FORMATS } from '@angular/material-moment-adapter';
|
||||||
|
|
||||||
import { SearchWidget } from '../../search-widget.interface';
|
import { SearchWidget } from '../../search-widget.interface';
|
||||||
import { SearchWidgetSettings } from '../../search-widget-settings.interface';
|
import { SearchWidgetSettings } from '../../search-widget-settings.interface';
|
||||||
import { SearchQueryBuilderService } from '../../search-query-builder.service';
|
import { SearchQueryBuilderService } from '../../search-query-builder.service';
|
||||||
import { LiveErrorStateMatcher } from '../../forms/live-error-state-matcher';
|
import { LiveErrorStateMatcher } from '../../forms/live-error-state-matcher';
|
||||||
import moment from 'moment-es6';
|
import { Moment } from 'moment';
|
||||||
|
import { UserPreferencesService, UserPreferenceValues } from '@alfresco/adf-core';
|
||||||
|
|
||||||
|
declare let moment: any;
|
||||||
|
|
||||||
|
const DEFAULT_FORMAT_DATE: string = 'DD/MM/YYYY';
|
||||||
|
|
||||||
|
export class CustomMomentDateAdapter extends MomentDateAdapter {
|
||||||
|
customDateFormat: string;
|
||||||
|
|
||||||
|
parse(value: any, parseFormat: any): any {
|
||||||
|
const dateFormat = this.customDateFormat ? this.customDateFormat : DEFAULT_FORMAT_DATE;
|
||||||
|
|
||||||
|
return super.parse(value, dateFormat);
|
||||||
|
}
|
||||||
|
|
||||||
|
format(value: Moment, displayFormat: string): string {
|
||||||
|
const dateFormat = this.customDateFormat ? this.customDateFormat : DEFAULT_FORMAT_DATE;
|
||||||
|
|
||||||
|
return super.format(value, dateFormat);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
@Component({
|
@Component({
|
||||||
selector: 'adf-search-date-range',
|
selector: 'adf-search-date-range',
|
||||||
templateUrl: './search-date-range.component.html',
|
templateUrl: './search-date-range.component.html',
|
||||||
styleUrls: ['./search-date-range.component.scss'],
|
styleUrls: ['./search-date-range.component.scss'],
|
||||||
|
providers: [
|
||||||
|
{provide: DateAdapter, useClass: CustomMomentDateAdapter, deps: [MAT_DATE_LOCALE]},
|
||||||
|
{provide: MAT_DATE_FORMATS, useValue: MAT_MOMENT_DATE_FORMATS}
|
||||||
|
],
|
||||||
encapsulation: ViewEncapsulation.None,
|
encapsulation: ViewEncapsulation.None,
|
||||||
host: { class: 'adf-search-date-range' }
|
host: { class: 'adf-search-date-range' }
|
||||||
})
|
})
|
||||||
@ -42,8 +70,23 @@ export class SearchDateRangeComponent implements SearchWidget, OnInit {
|
|||||||
settings?: SearchWidgetSettings;
|
settings?: SearchWidgetSettings;
|
||||||
context?: SearchQueryBuilderService;
|
context?: SearchQueryBuilderService;
|
||||||
maxFrom: any;
|
maxFrom: any;
|
||||||
|
datePickerDateFormat = DEFAULT_FORMAT_DATE;
|
||||||
|
|
||||||
|
constructor(private dateAdapter: DateAdapter<Moment>,
|
||||||
|
private userPreferencesService: UserPreferencesService) {
|
||||||
|
}
|
||||||
|
|
||||||
ngOnInit() {
|
ngOnInit() {
|
||||||
|
if (this.settings) {
|
||||||
|
this.datePickerDateFormat = this.settings.dateFormat || DEFAULT_FORMAT_DATE;
|
||||||
|
}
|
||||||
|
const theCustomDateAdapter = <CustomMomentDateAdapter> <any> this.dateAdapter;
|
||||||
|
theCustomDateAdapter.customDateFormat = this.datePickerDateFormat;
|
||||||
|
|
||||||
|
this.userPreferencesService.select(UserPreferenceValues.Locale).subscribe((locale) => {
|
||||||
|
this.setLocale(locale);
|
||||||
|
});
|
||||||
|
|
||||||
const validators = Validators.compose([
|
const validators = Validators.compose([
|
||||||
Validators.required
|
Validators.required
|
||||||
]);
|
]);
|
||||||
@ -80,13 +123,20 @@ export class SearchDateRangeComponent implements SearchWidget, OnInit {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
hasSelectedDays(from: string, to: string): boolean {
|
onChangedHandler(event: any, formControl) {
|
||||||
if (from && to) {
|
const inputValue = event.srcElement.value;
|
||||||
const start = moment(from).startOf('day');
|
|
||||||
const end = moment(to).endOf('day');
|
|
||||||
|
|
||||||
return start.isBefore(end);
|
if (inputValue) {
|
||||||
|
const formatDate = moment(inputValue, this.datePickerDateFormat);
|
||||||
|
|
||||||
|
if (formatDate.isValid()) {
|
||||||
|
formControl.setValue(formatDate);
|
||||||
}
|
}
|
||||||
return true;
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
setLocale(locale) {
|
||||||
|
this.dateAdapter.setLocale(locale);
|
||||||
|
moment.locale(locale);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
22
package-lock.json
generated
22
package-lock.json
generated
@ -49,6 +49,11 @@
|
|||||||
"superagent": "3.8.2"
|
"superagent": "3.8.2"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"moment": {
|
||||||
|
"version": "2.20.1",
|
||||||
|
"resolved": "https://registry.npmjs.org/moment/-/moment-2.20.1.tgz",
|
||||||
|
"integrity": "sha512-Yh9y73JRljxW5QxN08Fner68eFLxM5ynNOAw2LbIB1YAGeQzZT8QFSUvkAz609Zf+IHhhaUxqZK8dG3W/+HEvg=="
|
||||||
|
},
|
||||||
"pdfjs-dist": {
|
"pdfjs-dist": {
|
||||||
"version": "1.5.404",
|
"version": "1.5.404",
|
||||||
"resolved": "https://registry.npmjs.org/pdfjs-dist/-/pdfjs-dist-1.5.404.tgz",
|
"resolved": "https://registry.npmjs.org/pdfjs-dist/-/pdfjs-dist-1.5.404.tgz",
|
||||||
@ -108,6 +113,11 @@
|
|||||||
"superagent": "3.8.2"
|
"superagent": "3.8.2"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"moment": {
|
||||||
|
"version": "2.20.1",
|
||||||
|
"resolved": "https://registry.npmjs.org/moment/-/moment-2.20.1.tgz",
|
||||||
|
"integrity": "sha512-Yh9y73JRljxW5QxN08Fner68eFLxM5ynNOAw2LbIB1YAGeQzZT8QFSUvkAz609Zf+IHhhaUxqZK8dG3W/+HEvg=="
|
||||||
|
},
|
||||||
"pdfjs-dist": {
|
"pdfjs-dist": {
|
||||||
"version": "1.5.404",
|
"version": "1.5.404",
|
||||||
"resolved": "https://registry.npmjs.org/pdfjs-dist/-/pdfjs-dist-1.5.404.tgz",
|
"resolved": "https://registry.npmjs.org/pdfjs-dist/-/pdfjs-dist-1.5.404.tgz",
|
||||||
@ -168,6 +178,11 @@
|
|||||||
"superagent": "3.8.2"
|
"superagent": "3.8.2"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"moment": {
|
||||||
|
"version": "2.20.1",
|
||||||
|
"resolved": "https://registry.npmjs.org/moment/-/moment-2.20.1.tgz",
|
||||||
|
"integrity": "sha512-Yh9y73JRljxW5QxN08Fner68eFLxM5ynNOAw2LbIB1YAGeQzZT8QFSUvkAz609Zf+IHhhaUxqZK8dG3W/+HEvg=="
|
||||||
|
},
|
||||||
"pdfjs-dist": {
|
"pdfjs-dist": {
|
||||||
"version": "1.5.404",
|
"version": "1.5.404",
|
||||||
"resolved": "https://registry.npmjs.org/pdfjs-dist/-/pdfjs-dist-1.5.404.tgz",
|
"resolved": "https://registry.npmjs.org/pdfjs-dist/-/pdfjs-dist-1.5.404.tgz",
|
||||||
@ -229,6 +244,11 @@
|
|||||||
"superagent": "3.8.2"
|
"superagent": "3.8.2"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"moment": {
|
||||||
|
"version": "2.20.1",
|
||||||
|
"resolved": "https://registry.npmjs.org/moment/-/moment-2.20.1.tgz",
|
||||||
|
"integrity": "sha512-Yh9y73JRljxW5QxN08Fner68eFLxM5ynNOAw2LbIB1YAGeQzZT8QFSUvkAz609Zf+IHhhaUxqZK8dG3W/+HEvg=="
|
||||||
|
},
|
||||||
"pdfjs-dist": {
|
"pdfjs-dist": {
|
||||||
"version": "1.5.404",
|
"version": "1.5.404",
|
||||||
"resolved": "https://registry.npmjs.org/pdfjs-dist/-/pdfjs-dist-1.5.404.tgz",
|
"resolved": "https://registry.npmjs.org/pdfjs-dist/-/pdfjs-dist-1.5.404.tgz",
|
||||||
@ -10552,7 +10572,7 @@
|
|||||||
},
|
},
|
||||||
"moment": {
|
"moment": {
|
||||||
"version": "2.20.1",
|
"version": "2.20.1",
|
||||||
"resolved": "http://localhost:4873/moment/-/moment-2.20.1.tgz",
|
"resolved": "https://registry.npmjs.org/moment/-/moment-2.20.1.tgz",
|
||||||
"integrity": "sha512-Yh9y73JRljxW5QxN08Fner68eFLxM5ynNOAw2LbIB1YAGeQzZT8QFSUvkAz609Zf+IHhhaUxqZK8dG3W/+HEvg=="
|
"integrity": "sha512-Yh9y73JRljxW5QxN08Fner68eFLxM5ynNOAw2LbIB1YAGeQzZT8QFSUvkAz609Zf+IHhhaUxqZK8dG3W/+HEvg=="
|
||||||
},
|
},
|
||||||
"moment-es6": {
|
"moment-es6": {
|
||||||
|
@ -8,6 +8,7 @@ ADF_VERSION=$(npm view @alfresco/adf-core version)
|
|||||||
ANGULAR_VERSION="5.1.1"
|
ANGULAR_VERSION="5.1.1"
|
||||||
MATERIAL_VERSION="5.0.1"
|
MATERIAL_VERSION="5.0.1"
|
||||||
NGX_TRANSLATE_VERSION="9.1.1"
|
NGX_TRANSLATE_VERSION="9.1.1"
|
||||||
|
MOMENT_VERSION="2.20.1"
|
||||||
|
|
||||||
npm install
|
npm install
|
||||||
|
|
||||||
@ -21,5 +22,6 @@ npm install --save @mat-datetimepicker/core @mat-datetimepicker/moment
|
|||||||
npm install --save-exact --save @angular/animations@${ANGULAR_VERSION} @angular/common@${ANGULAR_VERSION} @angular/compiler@${ANGULAR_VERSION} @angular/core@${ANGULAR_VERSION} @angular/platform-browser@${ANGULAR_VERSION} @angular/router@${ANGULAR_VERSION} @angular/flex-layout@2.0.0-beta.12 @angular/forms@${ANGULAR_VERSION} @angular/forms@${ANGULAR_VERSION} @angular/http@${ANGULAR_VERSION} @angular/platform-browser-dynamic@${ANGULAR_VERSION}
|
npm install --save-exact --save @angular/animations@${ANGULAR_VERSION} @angular/common@${ANGULAR_VERSION} @angular/compiler@${ANGULAR_VERSION} @angular/core@${ANGULAR_VERSION} @angular/platform-browser@${ANGULAR_VERSION} @angular/router@${ANGULAR_VERSION} @angular/flex-layout@2.0.0-beta.12 @angular/forms@${ANGULAR_VERSION} @angular/forms@${ANGULAR_VERSION} @angular/http@${ANGULAR_VERSION} @angular/platform-browser-dynamic@${ANGULAR_VERSION}
|
||||||
npm install --save-exact --save @angular/cdk@${MATERIAL_VERSION} @angular/material@${MATERIAL_VERSION}
|
npm install --save-exact --save @angular/cdk@${MATERIAL_VERSION} @angular/material@${MATERIAL_VERSION}
|
||||||
npm install --save-exact --save @ngx-translate/core@${NGX_TRANSLATE_VERSION}
|
npm install --save-exact --save @ngx-translate/core@${NGX_TRANSLATE_VERSION}
|
||||||
|
npm install --save-exact --save moment@${MOMENT_VERSION}
|
||||||
|
|
||||||
npm run e2e
|
npm run e2e
|
||||||
|
Loading…
x
Reference in New Issue
Block a user