Unverified Commit 4a7f2f0e authored by Dmitriy Shekhovtsov's avatar Dmitriy Shekhovtsov Committed by GitHub
Browse files

feat(datepicker): added BsLocaleService to change datepicker locale (#3209)

* feat(datepicker): added BsLocaleService to change datepicker locale

* chore(datepicker): removed obsolete comments

* fix(datepicker): add BsLocaleService to exports

* demo(datepicker): change locale demo according to BsLocaleService
parent 735101c5
Showing with 100 additions and 35 deletions
+100 -35
...@@ -70,11 +70,11 @@ export const demoComponentContent: ContentSection[] = [ ...@@ -70,11 +70,11 @@ export const demoComponentContent: ContentSection[] = [
component: require('!!raw-loader?lang=typescript!./demos/change-locale/change-locale.ts'), component: require('!!raw-loader?lang=typescript!./demos/change-locale/change-locale.ts'),
html: require('!!raw-loader?lang=markup!./demos/change-locale/change-locale.html'), html: require('!!raw-loader?lang=markup!./demos/change-locale/change-locale.html'),
description: ` description: `
<p>Datepicker can use different locales. <br>It's possible to change a locale by changing <p>Datepicker can use different locales. <br>It's possible to change a locale by calling
<code>locale</code> <code>use</code>
property in <code>bsConfig</code> object, list of available locales is in dropdown below.</p> method of <code>BsLocaleService</code>, list of available locales is in dropdown below.</p>
<p>To use a different locale, you have to import it from <code>ngx-bootstrap/bs-moment</code> and define it <p>To use a different locale, you have to import it from <code>ngx-bootstrap/bs-moment</code> first, then
in your <code>@NgModule</code> using function <code>defineLocale</code></p> define it in your <code>@NgModule</code> using function <code>defineLocale</code></p>
<p>Example: </p> <p>Example: </p>
<code>import { defineLocale } from 'ngx-bootstrap/bs-moment';</code><br> <code>import { defineLocale } from 'ngx-bootstrap/bs-moment';</code><br>
<code>import { de } from 'ngx-bootstrap/locale';</code><br> <code>import { de } from 'ngx-bootstrap/locale';</code><br>
......
...@@ -7,7 +7,7 @@ ...@@ -7,7 +7,7 @@
</select> </select>
</div> </div>
<div class="col-xs-6 col-6 col-md-4 col-lg-3 form-group"> <div class="col-xs-6 col-6 col-md-4 col-lg-3 form-group">
<input placeholder="Datepicker" type="text" class="form-control" bsDatepicker #dp="bsDatepicker" [bsConfig]="bsConfig"> <input placeholder="Datepicker" type="text" class="form-control" bsDatepicker #dp="bsDatepicker">
</div> </div>
<div class="col-xs-12 col-12 col-md-4 col-lg-4 form-group"> <div class="col-xs-12 col-12 col-md-4 col-lg-4 form-group">
<input type="button" <input type="button"
...@@ -27,7 +27,7 @@ ...@@ -27,7 +27,7 @@
</select> </select>
</div> </div>
<div class="col-xs-6 col-6 col-md-4 col-lg-3 form-group"> <div class="col-xs-6 col-6 col-md-4 col-lg-3 form-group">
<input placeholder="Daterangepicker" type="text" class="form-control" bsDaterangepicker #dpr="bsDaterangepicker" [bsConfig]="bsConfig"> <input placeholder="Daterangepicker" type="text" class="form-control" bsDaterangepicker #dpr="bsDaterangepicker">
</div> </div>
<div class="col-xs-12 col-12 col-md-4 col-lg-4 form-group"> <div class="col-xs-12 col-12 col-md-4 col-lg-4 form-group">
<input type="button" <input type="button"
......
import { Component } from '@angular/core'; import { Component } from '@angular/core';
import { BsDatepickerConfig } from 'ngx-bootstrap/datepicker'; import { BsDatepickerConfig, BsLocaleService } from 'ngx-bootstrap/datepicker';
import { listLocales } from 'ngx-bootstrap/bs-moment'; import { listLocales } from 'ngx-bootstrap/bs-moment';
@Component({ @Component({
...@@ -9,15 +9,13 @@ import { listLocales } from 'ngx-bootstrap/bs-moment'; ...@@ -9,15 +9,13 @@ import { listLocales } from 'ngx-bootstrap/bs-moment';
export class DemoDatepickerChangeLocaleComponent { export class DemoDatepickerChangeLocaleComponent {
locale = 'en'; locale = 'en';
locales = listLocales(); locales = listLocales();
bsConfig: Partial<BsDatepickerConfig>;
constructor(private _localeService: BsLocaleService) {
}
applyLocale(pop: any) { applyLocale(pop: any) {
// create new object on each property change this._localeService.use(this.locale);
// so Angular can catch object reference change pop.hide();
this.bsConfig = Object.assign({}, { locale: this.locale }); pop.show();
setTimeout(() => {
pop.hide();
pop.show();
});
} }
} }
...@@ -3,6 +3,7 @@ import { ControlValueAccessor, NG_VALUE_ACCESSOR } from '@angular/forms'; ...@@ -3,6 +3,7 @@ import { ControlValueAccessor, NG_VALUE_ACCESSOR } from '@angular/forms';
import { BsDatepickerDirective } from './bs-datepicker.component'; import { BsDatepickerDirective } from './bs-datepicker.component';
import { formatDate } from '../bs-moment/format'; import { formatDate } from '../bs-moment/format';
import { getLocale } from '../bs-moment/locale/locales.service'; import { getLocale } from '../bs-moment/locale/locales.service';
import { BsLocaleService } from './bs-locale.service';
const BS_DATEPICKER_VALUE_ACCESSOR = { const BS_DATEPICKER_VALUE_ACCESSOR = {
provide: NG_VALUE_ACCESSOR, provide: NG_VALUE_ACCESSOR,
...@@ -27,9 +28,11 @@ export class BsDatepickerInputDirective ...@@ -27,9 +28,11 @@ export class BsDatepickerInputDirective
private _value: Date; private _value: Date;
constructor(@Host() private _picker: BsDatepickerDirective, constructor(@Host() private _picker: BsDatepickerDirective,
private _localeService: BsLocaleService,
private _renderer: Renderer2, private _renderer: Renderer2,
private _elRef: ElementRef, private _elRef: ElementRef,
private changeDetection: ChangeDetectorRef) { private changeDetection: ChangeDetectorRef) {
// update input value on datepicker value update
this._picker.bsValueChange.subscribe((value: Date) => { this._picker.bsValueChange.subscribe((value: Date) => {
this._setInputValue(value); this._setInputValue(value);
if (this._value !== value) { if (this._value !== value) {
...@@ -39,13 +42,18 @@ export class BsDatepickerInputDirective ...@@ -39,13 +42,18 @@ export class BsDatepickerInputDirective
} }
this.changeDetection.markForCheck(); this.changeDetection.markForCheck();
}); });
// update input value on locale change
this._localeService.localeChange.subscribe(() => {
this._setInputValue(this._value);
});
} }
_setInputValue(value: Date): void { _setInputValue(value: Date): void {
const initialDate = formatDate( const initialDate = formatDate(
value, value,
this._picker._config.dateInputFormat, this._picker._config.dateInputFormat,
this._picker._config.locale this._localeService.currentLocale
) || ''; ) || '';
this._renderer.setProperty(this._elRef.nativeElement, 'value', initialDate); this._renderer.setProperty(this._elRef.nativeElement, 'value', initialDate);
} }
...@@ -60,11 +68,11 @@ export class BsDatepickerInputDirective ...@@ -60,11 +68,11 @@ export class BsDatepickerInputDirective
if (!value) { if (!value) {
this._value = null; this._value = null;
} }
const _locale = getLocale(this._picker._config.locale); const _localeKey = this._localeService.currentLocale;
const _locale = getLocale(_localeKey);
if (!_locale) { if (!_locale) {
throw new Error( throw new Error(
`Locale "${this._picker._config `Locale "${_localeKey}" is not defined, please add it with "defineLocale(...)"`
.locale}" is not defined, please add it with "defineLocale(...)"`
); );
} }
if (typeof value === 'string') { if (typeof value === 'string') {
......
...@@ -8,6 +8,7 @@ import { BsDatepickerContainerComponent } from './themes/bs/bs-datepicker-contai ...@@ -8,6 +8,7 @@ import { BsDatepickerContainerComponent } from './themes/bs/bs-datepicker-contai
import { Subscription } from 'rxjs/Subscription'; import { Subscription } from 'rxjs/Subscription';
import 'rxjs/add/operator/filter'; import 'rxjs/add/operator/filter';
import { BsDatepickerConfig } from './bs-datepicker.config'; import { BsDatepickerConfig } from './bs-datepicker.config';
import { BsLocaleService } from './bs-locale.service';
@Directive({ @Directive({
selector: '[bsDatepicker]', selector: '[bsDatepicker]',
......
...@@ -6,7 +6,7 @@ import { ...@@ -6,7 +6,7 @@ import {
@Injectable() @Injectable()
export class BsDatepickerConfig export class BsDatepickerConfig
implements DatepickerRenderOptions, DatepickerFormatOptions { implements DatepickerRenderOptions {
value?: Date | Date[]; value?: Date | Date[];
isDisabled?: boolean; isDisabled?: boolean;
/** /**
...@@ -36,11 +36,6 @@ export class BsDatepickerConfig ...@@ -36,11 +36,6 @@ export class BsDatepickerConfig
rangeInputFormat = 'L'; rangeInputFormat = 'L';
// DatepickerFormatOptions // DatepickerFormatOptions
/**
* Allows to globally set default locale of datepicker,
* see documentation on how to enable custom locales
*/
locale = 'en';
monthTitle = 'MMMM'; monthTitle = 'MMMM';
yearTitle = 'YYYY'; yearTitle = 'YYYY';
dayLabel = 'D'; dayLabel = 'D';
......
...@@ -22,6 +22,8 @@ import { BsCalendarLayoutComponent } from './themes/bs/bs-calendar-layout.compon ...@@ -22,6 +22,8 @@ import { BsCalendarLayoutComponent } from './themes/bs/bs-calendar-layout.compon
import { BsDatepickerInputDirective } from './bs-datepicker-input.directive'; import { BsDatepickerInputDirective } from './bs-datepicker-input.directive';
import { BsDaterangepickerInputDirective } from './bs-daterangepicker-input.directive'; import { BsDaterangepickerInputDirective } from './bs-daterangepicker-input.directive';
import { BsLocaleService } from './bs-locale.service';
import { warnOnce } from '../utils/warn-once'; import { warnOnce } from '../utils/warn-once';
const _exports = [ const _exports = [
...@@ -74,7 +76,8 @@ export class BsDatepickerModule { ...@@ -74,7 +76,8 @@ export class BsDatepickerModule {
BsDatepickerStore, BsDatepickerStore,
BsDatepickerActions, BsDatepickerActions,
BsDatepickerConfig, BsDatepickerConfig,
BsDatepickerEffects BsDatepickerEffects,
BsLocaleService
] ]
}; };
} }
......
...@@ -3,6 +3,7 @@ import { ControlValueAccessor, NG_VALUE_ACCESSOR } from '@angular/forms'; ...@@ -3,6 +3,7 @@ import { ControlValueAccessor, NG_VALUE_ACCESSOR } from '@angular/forms';
import { formatDate } from '../bs-moment/format'; import { formatDate } from '../bs-moment/format';
import { getLocale } from '../bs-moment/locale/locales.service'; import { getLocale } from '../bs-moment/locale/locales.service';
import { BsDaterangepickerDirective } from './bs-daterangepicker.component'; import { BsDaterangepickerDirective } from './bs-daterangepicker.component';
import { BsLocaleService } from './bs-locale.service';
const BS_DATERANGEPICKER_VALUE_ACCESSOR = { const BS_DATERANGEPICKER_VALUE_ACCESSOR = {
provide: NG_VALUE_ACCESSOR, provide: NG_VALUE_ACCESSOR,
...@@ -27,9 +28,11 @@ export class BsDaterangepickerInputDirective ...@@ -27,9 +28,11 @@ export class BsDaterangepickerInputDirective
private _value: Date[]; private _value: Date[];
constructor(@Host() private _picker: BsDaterangepickerDirective, constructor(@Host() private _picker: BsDaterangepickerDirective,
private _localeService: BsLocaleService,
private _renderer: Renderer2, private _renderer: Renderer2,
private _elRef: ElementRef, private _elRef: ElementRef,
private changeDetection: ChangeDetectorRef) { private changeDetection: ChangeDetectorRef) {
// update input value on datepicker value update
this._picker.bsValueChange.subscribe((value: Date[]) => { this._picker.bsValueChange.subscribe((value: Date[]) => {
this._setInputValue(value); this._setInputValue(value);
if (this._value !== value) { if (this._value !== value) {
...@@ -39,6 +42,11 @@ export class BsDaterangepickerInputDirective ...@@ -39,6 +42,11 @@ export class BsDaterangepickerInputDirective
} }
this.changeDetection.markForCheck(); this.changeDetection.markForCheck();
}); });
// update input value on locale change
this._localeService.localeChange.subscribe(() => {
this._setInputValue(this._value);
});
} }
_setInputValue(date: Date[]): void { _setInputValue(date: Date[]): void {
...@@ -47,12 +55,12 @@ export class BsDaterangepickerInputDirective ...@@ -47,12 +55,12 @@ export class BsDaterangepickerInputDirective
const start = formatDate( const start = formatDate(
date[0], date[0],
this._picker._config.rangeInputFormat, this._picker._config.rangeInputFormat,
this._picker._config.locale this._localeService.currentLocale
) || ''; ) || '';
const end = formatDate( const end = formatDate(
date[1], date[1],
this._picker._config.rangeInputFormat, this._picker._config.rangeInputFormat,
this._picker._config.locale this._localeService.currentLocale
) || ''; ) || '';
range = (start && end) ? start + this._picker._config.rangeSeparator + end : ''; range = (start && end) ? start + this._picker._config.rangeSeparator + end : '';
} }
...@@ -70,11 +78,11 @@ export class BsDaterangepickerInputDirective ...@@ -70,11 +78,11 @@ export class BsDaterangepickerInputDirective
this._value = null; this._value = null;
} }
const _locale = getLocale(this._picker._config.locale); const _localeKey = this._localeService.currentLocale;
const _locale = getLocale(_localeKey);
if (!_locale) { if (!_locale) {
throw new Error( throw new Error(
`Locale "${this._picker._config `Locale "${_localeKey}" is not defined, please add it with "defineLocale(...)"`
.locale}" is not defined, please add it with "defineLocale(...)"`
); );
} }
......
import { Injectable } from '@angular/core';
import { Observable } from 'rxjs/Observable';
import { BehaviorSubject } from 'rxjs/BehaviorSubject';
@Injectable()
export class BsLocaleService {
private _defaultLocale = 'en';
private _locale = new BehaviorSubject<string>(this._defaultLocale);
private _localeChange: Observable<string> = this._locale.asObservable();
get locale(): BehaviorSubject<string> {
return this._locale;
}
get localeChange(): Observable<string> {
return this._localeChange;
}
get currentLocale(): string {
return this._locale.getValue();
}
use(locale: string): void {
if (locale === this.currentLocale) {
return;
}
this._locale.next(locale);
}
}
...@@ -10,3 +10,4 @@ export { BsDatepickerModule } from './bs-datepicker.module'; ...@@ -10,3 +10,4 @@ export { BsDatepickerModule } from './bs-datepicker.module';
export { BsDatepickerDirective } from './bs-datepicker.component'; export { BsDatepickerDirective } from './bs-datepicker.component';
export { BsDaterangepickerDirective } from './bs-daterangepicker.component'; export { BsDaterangepickerDirective } from './bs-daterangepicker.component';
export { BsDatepickerConfig } from './bs-datepicker.config'; export { BsDatepickerConfig } from './bs-datepicker.config';
export { BsLocaleService } from './bs-locale.service';
...@@ -24,6 +24,8 @@ export class BsDatepickerActions { ...@@ -24,6 +24,8 @@ export class BsDatepickerActions {
static readonly SET_MAX_DATE = '[datepicker] set max date'; static readonly SET_MAX_DATE = '[datepicker] set max date';
static readonly SET_IS_DISABLED = '[datepicker] set is disabled'; static readonly SET_IS_DISABLED = '[datepicker] set is disabled';
static readonly SET_LOCALE = '[datepicker] set datepicker locale';
static readonly SELECT_RANGE = '[daterangepicker] select dates range'; static readonly SELECT_RANGE = '[daterangepicker] select dates range';
calculate(): Action { calculate(): Action {
...@@ -108,4 +110,11 @@ export class BsDatepickerActions { ...@@ -108,4 +110,11 @@ export class BsDatepickerActions {
payload: value payload: value
}; };
} }
setLocale(locale: string): Action {
return {
type: BsDatepickerActions.SET_LOCALE,
payload: locale
};
}
} }
...@@ -19,6 +19,7 @@ import { ...@@ -19,6 +19,7 @@ import {
import { BsDatepickerActions } from './bs-datepicker.actions'; import { BsDatepickerActions } from './bs-datepicker.actions';
import { BsDatepickerStore } from './bs-datepicker.store'; import { BsDatepickerStore } from './bs-datepicker.store';
import { Subscription } from 'rxjs/Subscription'; import { Subscription } from 'rxjs/Subscription';
import { BsLocaleService } from '../bs-locale.service';
@Injectable() @Injectable()
export class BsDatepickerEffects { export class BsDatepickerEffects {
...@@ -31,7 +32,8 @@ export class BsDatepickerEffects { ...@@ -31,7 +32,8 @@ export class BsDatepickerEffects {
private _store: BsDatepickerStore; private _store: BsDatepickerStore;
private _subs: Subscription[] = []; private _subs: Subscription[] = [];
constructor(private _actions: BsDatepickerActions) {} constructor(private _actions: BsDatepickerActions,
private _localeService: BsLocaleService) {}
init(_bsDatepickerStore: BsDatepickerStore): BsDatepickerEffects { init(_bsDatepickerStore: BsDatepickerStore): BsDatepickerEffects {
this._store = _bsDatepickerStore; this._store = _bsDatepickerStore;
...@@ -69,7 +71,8 @@ export class BsDatepickerEffects { ...@@ -69,7 +71,8 @@ export class BsDatepickerEffects {
/* Set rendering options */ /* Set rendering options */
setOptions(_config: BsDatepickerConfig): BsDatepickerEffects { setOptions(_config: BsDatepickerConfig): BsDatepickerEffects {
this._store.dispatch(this._actions.setOptions(_config)); const _options = Object.assign({locale: this._localeService.currentLocale}, _config);
this._store.dispatch(this._actions.setOptions(_options));
return this; return this;
} }
...@@ -224,6 +227,12 @@ export class BsDatepickerEffects { ...@@ -224,6 +227,12 @@ export class BsDatepickerEffects {
.subscribe(hoveredDate => this._store.dispatch(this._actions.flag())) .subscribe(hoveredDate => this._store.dispatch(this._actions.flag()))
); );
// on locale change
this._subs.push(
this._localeService.localeChange
.subscribe(locale => this._store.dispatch(this._actions.setLocale(locale)))
)
return this; return this;
} }
......
...@@ -73,6 +73,7 @@ const _initialView: BsDatepickerViewState = { date: new Date(), mode: 'day' }; ...@@ -73,6 +73,7 @@ const _initialView: BsDatepickerViewState = { date: new Date(), mode: 'day' };
export const initialDatepickerState: BsDatepickerState = Object.assign( export const initialDatepickerState: BsDatepickerState = Object.assign(
new BsDatepickerConfig(), new BsDatepickerConfig(),
{ {
locale: 'en',
view: _initialView, view: _initialView,
selectedRange: [], selectedRange: [],
monthViewOptions: defaultMonthOptions monthViewOptions: defaultMonthOptions
......
...@@ -7,6 +7,7 @@ import { BsDatepickerActions } from '../../reducer/bs-datepicker.actions'; ...@@ -7,6 +7,7 @@ import { BsDatepickerActions } from '../../reducer/bs-datepicker.actions';
import { BsDatepickerEffects } from '../../reducer/bs-datepicker.effects'; import { BsDatepickerEffects } from '../../reducer/bs-datepicker.effects';
import { BsDatepickerStore } from '../../reducer/bs-datepicker.store'; import { BsDatepickerStore } from '../../reducer/bs-datepicker.store';
import { Subscription } from 'rxjs/Subscription'; import { Subscription } from 'rxjs/Subscription';
import { BsLocaleService } from '../../bs-locale.service';
@Component({ @Component({
selector: 'bs-datepicker-container', selector: 'bs-datepicker-container',
......
...@@ -52,7 +52,8 @@ export { ...@@ -52,7 +52,8 @@ export {
MonthPickerComponent, MonthPickerComponent,
YearPickerComponent, YearPickerComponent,
BsDatepickerModule, BsDatepickerModule,
BsDatepickerConfig BsDatepickerConfig,
BsLocaleService
} from './datepicker'; } from './datepicker';
export { export {
......
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment