Change language of Datepicker of Material Angular 4 - javascript

How to Change language of Datepicker of Material Angular?
I can't find in documentation for Angular material 2.
Here is a plunkr https://plnkr.co/edit/unzlijtsHf3CPW4oL7bl?p=preview
<md-input-container>
<input mdInput [mdDatepicker]="picker" placeholder="Choose a date">
<button mdSuffix [mdDatepickerToggle]="picker"></button>
</md-input-container>
<md-datepicker #picker></md-datepicker>

import {MAT_DATE_LOCALE} from '#angular/material';
&
providers: [{ provide: MAT_DATE_LOCALE, useValue: 'es-ES' }]
Do this in tpv.modules.ts

md-datepicker provides setLocale method which can be used to set any language (list of locale).
Here's an example of setting locale to 'fr':
export class DatepickerOverviewExample {
constructor(private dateAdapter: DateAdapter<Date>) {
this.dateAdapter.setLocale('fr');
}
}
One thing to keep in mind, md-datepicker's default date parsing format is mm/dd/yyyy, so if a locale has a different date format (for 'fr' its dd/mm/yyyy), we will need to define a class that extends NativeDateAdapter to parse the new date format. Without setting the proper date format, there will be an issue like this question.
import { NativeDateAdapter, DateAdapter, MD_DATE_FORMATS } from "#angular/material/core";
export class FrenchDateAdapter extends NativeDateAdapter {
parse(value: any): Date | null {
if ((typeof value === 'string') && (value.indexOf('/') > -1)) {
const str = value.split('/');
if (str.length < 2 || isNaN(+str[0]) || isNaN(+str[1]) || isNaN(+str[2])) {
return null;
}
return new Date(Number(str[2]), Number(str[1]) - 1, Number(str[0]), 12);
}
const timestamp = typeof value === 'number' ? value : Date.parse(value);
return isNaN(timestamp) ? null : new Date(timestamp);
}
}
#Component({
...
providers: [{provide: DateAdapter, useClass: FrenchDateAdapter}],
})
Plunker demo

Locale setting can be provided via MAT_DATE_LOCALE constant, but to change language dynamically you need to use DateAdapter as it is shown in https://material.angular.io/components/datepicker/overview#internationalization
#Component({
selector: 'app-root',
templateUrl: './app.component.html'
})
export class AppComponent {
constructor(private dateAdapter: DateAdapter<any>) {}
setFrench() {
// Set language of Datepicker
this.dateAdapter.setLocale('fr');
}
}
Here is another example when you need to configure locale from external script:
<script>
window.appConfig = {
language: 'fr',
// Other config options
// ...
};
<script>
<app-root></app-root>
In this case you should also use DateAdapter:
import {Injectable} from '#angular/core';
import {DateAdapter} from '#angular/material';
declare let window: any;
#Injectable()
export class AppConfigService {
appConfig = window.appConfig;
constructor(private dateAdapter: DateAdapter<any>) {
// Set language of Datepicker
this.dateAdapter.setLocale(this.appConfig.language);
}
}

For anyone who has a bug when editing input field (eg: putting DD/MM/YYYY will change it to MM/DD/YYYY or simply not working) create an adapter:
import { NativeDateAdapter } from '#angular/material';
export class FrenchDateProvider extends NativeDateAdapter {
parse(value: string) {
let it = value.split('/');
if (it.length == 3) {
return new Date(+it[2], +it[1] - 1, +it[0], 12);
}
}
format(date: Date, displayFormat: Object) {
return ('0' + date.getDate()).slice(-2) + '/' + ('0' + (date.getMonth() + 1)).slice(-2) + '/' + date.getFullYear();
}
}
Add it to your module as provider:
#NgModule({
providers: [
{ provide: DateAdapter, useClass: FrenchDateProvider }
]
})
export class SharedModule { }

For me the working solution is similar to vladernn's, however it should be:
import {MAT_DATE_LOCALE} from '#angular/material/core';
and
providers: [{ provide: MAT_DATE_LOCALE, useValue: 'pl' }]
in material.module.ts file.
Difference: new import address and shorter useValue code.

I tried this and worked for me
constructor(private _adapter: DateAdapter<any>, private translate:TranslateService ) {
this._adapter.setLocale(this.translate.getBrowserLang());
}

Related

How can i format input fields as currency in Angular

I am working on an Angular project and I have an object of type Project that contains the following values:
cost: 56896 and
costHR: 27829
I want to modify the object using a form and bind the fields with ngModel to the attributes.
But the problem I am facing is that in the field, I want to display the number in a currency format (e.g. 56,896€) which is not compatible with the variable type which is float.
Can someone help me with a solution to this problem? I have tried using built-in Angular pipes and custom formatter and parser functions, but none of them seem to work as expected.
Any help would be greatly appreciated.
import { Component, OnInit } from '#angular/core';
import { CurrencyPipe } from '#angular/common';
#Component({
selector: 'app-root',
templateUrl: './app.component.html',
styleUrls: ['./app.component.css'],
providers: [CurrencyPipe]
})
export class AppComponent implements OnInit {
project = {
cost: 56896,
costRH: 27829
}
constructor(private currencyPipe: CurrencyPipe) { }
ngOnInit() {
this.project.cost = this.currencyPipe.transform(this.project.cost, 'EUR', 'symbol', '1.0-0');
this.project.costRH = this.currencyPipe.transform(this.project.costRH, 'EUR', 'symbol', '1.0-0');
}
onBlur(event, projectProperty) {
this.project[projectProperty] = this.currencyPipe.parse(event.target.value);
}
}
<form>
<label for="cost">Cost</label>
<input [(ngModel)]="project.cost" (blur)="onBlur($event, 'cost')" [ngModelOptions]="{updateOn: 'blur'}" [value]="project.cost | currency:'EUR':'symbol':'1.0-0'">
<label for="costRH">Cost RH</label>
<input [(ngModel)]="project.costRH" (blur)="onBlur($event, 'costRH')" [ngModelOptions]="{updateOn: 'blur'}" [value]="project.costRH | currency:'EUR':'symbol':'1.0-0'">
</form>
What I expected:
I expected the input fields to be formatted as currency (e.g. 56,896€) and for the corresponding properties in the 'projet' object (cost and costRH) to be updated with the parsed value when the input loses focus.
What happened instead:
The value displayed in the input fields is not formatted as currency and the corresponding properties in the object are not being updated as expected.
you can use a directive like
#Directive({
selector: '[format]',
})
export class FormatDirective implements OnInit {
format = 'N0';
digitsInfo = '1.0-0';
#Input() currency = '$';
#Input() sufix = '';
#Input() decimalCharacter = null;
#Input('format') set _(value: string) {
this.format = value;
if (this.format == 'N2') this.digitsInfo = '1.2-2';
const parts = value.split(':');
if (parts.length > 1) {
this.format = value[0];
this.digitsInfo = parts[1];
}
}
#HostListener('blur', ['$event.target']) blur(target: any) {
target.value = this.parse(target.value);
}
#HostListener('focus', ['$event.target']) focus(target: any) {
target.value = this.control.value;
}
ngOnInit() {
setTimeout(() => {
this.el.nativeElement.value = this.parse(this.el.nativeElement.value);
});
}
constructor(
#Inject(LOCALE_ID) private locale: string,
private el: ElementRef,
private control: NgControl
) {}
parse(value: any) {
let newValue = value;
if (this.format == 'C2')
newValue = formatCurrency(value, this.locale, this.currency);
if (this.format == 'N2')
newValue = formatNumber(value, this.locale, this.digitsInfo);
if (this.format == 'N0')
newValue = formatNumber(value, this.locale, this.digitsInfo);
if (this.format == 'NX')
newValue = formatNumber(value, this.locale, this.digitsInfo);
if (this.decimalCharacter)
return (
newValue.replace('.', 'x').replace(',', '.').replace('x', ',') +
this.sufix
);
return newValue + this.sufix;
}
}
Works like
<input format="N0" [(ngModel)]="value"/>
<input format="N2" [(ngModel)]="value"/>
<input format="C2" [(ngModel)]="value"/>
<input format="N2" decimalCharacter='.' sufix=' €' [(ngModel)]="value"/>
The idea of the directive is that, when blur, change the "native Element", but not the value of the ngControl, when focus return the value of the ngControl
The stackblitz
I have used Numberal js for formatting numbers and it was awesome
Your desired format is this one '0,0[.]00 €'
check docs

Angular Material DatePicker: Month and Day, Exclude Year

How do I create a Month and Day Date Picker in Angular, excluding hide year?
This following link will do a Month and Year picker. I am trying to manipulate it, to do Month and Day. Replacing YYYY with DD is not working.
Stackblitz:
https://stackblitz.com/angular/gxymgjpprdy?file=src%2Fapp%2Fdatepicker-views-selection-example.ts
Real code from Stackblitz:
Typescript:
import {Component} from '#angular/core';
import {FormControl} from '#angular/forms';
import {MomentDateAdapter, MAT_MOMENT_DATE_ADAPTER_OPTIONS} from '#angular/material-moment-adapter';
import {DateAdapter, MAT_DATE_FORMATS, MAT_DATE_LOCALE} from '#angular/material/core';
import {MatDatepicker} from '#angular/material/datepicker';
// Depending on whether rollup is used, moment needs to be imported differently.
// Since Moment.js doesn't have a default export, we normally need to import using the `* as`
// syntax. However, rollup creates a synthetic default module and we thus need to import it using
// the `default as` syntax.
import * as _moment from 'moment';
// tslint:disable-next-line:no-duplicate-imports
import {default as _rollupMoment, Moment} from 'moment';
const moment = _rollupMoment || _moment;
// See the Moment.js docs for the meaning of these formats:
// https://momentjs.com/docs/#/displaying/format/
export const MY_FORMATS = {
parse: {
dateInput: 'MM/YYYY',
},
display: {
dateInput: 'MM/YYYY',
monthYearLabel: 'MMM YYYY',
dateA11yLabel: 'LL',
monthYearA11yLabel: 'MMMM YYYY',
},
};
/** #title Datepicker emulating a Year and month picker */
#Component({
selector: 'datepicker-views-selection-example',
templateUrl: 'datepicker-views-selection-example.html',
styleUrls: ['datepicker-views-selection-example.css'],
providers: [
// `MomentDateAdapter` can be automatically provided by importing `MomentDateModule` in your
// application's root module. We provide it at the component level here, due to limitations of
// our example generation script.
{
provide: DateAdapter,
useClass: MomentDateAdapter,
deps: [MAT_DATE_LOCALE, MAT_MOMENT_DATE_ADAPTER_OPTIONS]
},
{provide: MAT_DATE_FORMATS, useValue: MY_FORMATS},
],
})
export class DatepickerViewsSelectionExample {
date = new FormControl(moment());
chosenYearHandler(normalizedYear: Moment) {
const ctrlValue = this.date.value;
ctrlValue.year(normalizedYear.year());
this.date.setValue(ctrlValue);
}
chosenMonthHandler(normalizedMonth: Moment, datepicker: MatDatepicker<Moment>) {
const ctrlValue = this.date.value;
ctrlValue.month(normalizedMonth.month());
this.date.setValue(ctrlValue);
datepicker.close();
}
}
HTML:
<mat-form-field>
<input matInput [matDatepicker]="dp" placeholder="Month and Year" [formControl]="date">
<mat-datepicker-toggle matSuffix [for]="dp"></mat-datepicker-toggle>
<mat-datepicker #dp
startView="multi-year"
(yearSelected)="chosenYearHandler($event)"
(monthSelected)="chosenMonthHandler($event, dp)"
panelClass="example-month-picker">
</mat-datepicker>
</mat-form-field>
I do not want year option below in green, would like to disable year
Other Resources:
https://material.angular.io/components/datepicker/overview#watching-the-views-for-changes-on-selected-years-and-months
Angular Material Date picker disable the year selection
I hope you are expecting date format like DD/MMM. If so then change dateInput in display and parse object like below
dateInput: 'DD/MMM'
Hope this helps.
Here is the stackblitz code.
https://stackblitz.com/edit/angular-hw54xf
So , first in the html file
<mat-form-field class="mat-50-left" (click)="updateCalendarUI()">
<input matInput [matDatepicker]="picker_start"
placeholder="Date de début" required formControlName="dt_start" (click)="picker_start.open();">
<mat-datepicker-toggle matSuffix (click)="picker_end.open(); updateCalendarUI()"></mat-datepicker-toggle>
<mat-datepicker #picker_start startView="year"></mat-datepicker>
</mat-form-field>
in the .ts file
import {DateAdapter, NativeDateAdapter} from "#angular/material/core";
import * as moment from "moment";
export class AppDateAdapter extends NativeDateAdapter {
format(date: Date, displayFormat: Object): string {
// use what format you need
return moment(date).format('DD MMM');
}
}
add in providers
providers: [{provide: DateAdapter, useClass: AppDateAdapter}]
To update calendar UI
updateCalendarUI(): void {
setTimeout(() => {
let calendar = document.getElementsByClassName('mat-
calendar').item(0);
if (calendar) {
calendar['style'].height = '275px';
calendar['style']['padding-top'] = '15px';
}
let header = document.getElementsByClassName('mat-calendar-
header').item(0);
if (header) {
header['style'].display = 'none';
}
let yearLabel = document.getElementsByClassName('mat-calendar-body-
label').item(0);
if (yearLabel) {
yearLabel['style'].display = 'none';
}
}, 1);
}

How to get date and time in mm-dd-yyy hh-mm-ss in typescript?

Currently, I am getting date time in the following format 'mm/dd/yyyy, hh:mm:ss'.
How to get it in the following format 'mm-dd-yyyy hh-mm-ss'.
How to achieve this without using any library, and preferably by passing some args to the function itself?
Below is the code that am currently using (in Angular 5)
console.log(new Date().toLocaleString(undefined, { hour12: false }));
make use of DatePipe , that is provided by angular framework
{{ strDate | date :'MM-dd-yyyy hh-mm-ss' }
or in code you can do like this
import { DatePipe } from '#angular/common';
#Component({
selector: 'test-component',
templateUrl: './test-component.component.html'
})
class TestComponent {
constructor(private datePipe: DatePipe) {}
formatDate(date= new Date()) {
return this.datePipe.transform(date,'MM-dd-yyyy hh-mm-ss' );
}
}
check here : DatePipe

How to set locale in DatePipe in Angular 2?

I want to display Date using European format dd/MM/yyyy but using DatePipe shortDate format it only display using US date style MM/dd/yyyy.
I'm assuming thats the default locale is en_US. Maybe I am missing in the docs but how can I change the default locale settings in an Angular2 app? Or maybe is there some way to pass a custom format to DatePipe ?
As of Angular2 RC6, you can set default locale in your app module, by adding a provider:
#NgModule({
providers: [
{ provide: LOCALE_ID, useValue: "en-US" }, //replace "en-US" with your locale
//otherProviders...
]
})
The Currency/Date/Number pipes should pick up the locale. LOCALE_ID is an OpaqueToken, to be imported from angular/core.
import { LOCALE_ID } from '#angular/core';
For a more advanced use case, you may want to pick up locale from a service. Locale will be resolved (once) when component using date pipe is created:
{
provide: LOCALE_ID,
deps: [SettingsService], //some service handling global settings
useFactory: (settingsService) => settingsService.getLanguage() //returns locale string
}
Hope it works for you.
Solution with LOCALE_ID is great if you want to set the language for your app once. But it doesn’t work, if you want to change the language during runtime. For this case you can implement custom date pipe.
import { DatePipe } from '#angular/common';
import { Pipe, PipeTransform } from '#angular/core';
import { TranslateService } from '#ngx-translate/core';
#Pipe({
name: 'localizedDate',
pure: false
})
export class LocalizedDatePipe implements PipeTransform {
constructor(private translateService: TranslateService) {
}
transform(value: any, pattern: string = 'mediumDate'): any {
const datePipe: DatePipe = new DatePipe(this.translateService.currentLang);
return datePipe.transform(value, pattern);
}
}
Now if you change the app display language using TranslateService (see ngx-translate)
this.translateService.use('en');
the formats within your app should automatically being updated.
Example of use:
<p>{{ 'note.created-at' | translate:{date: note.createdAt | localizedDate} }}</p>
<p>{{ 'note.updated-at' | translate:{date: note.updatedAt | localizedDate:'fullDate'} }}</p>
or check my simple "Notes" project here.
With angular5 the above answer no longer works!
The following code:
app.module.ts
#NgModule({
providers: [
{ provide: LOCALE_ID, useValue: "de-at" }, //replace "de-at" with your locale
//otherProviders...
]
})
Leads to following error:
Error: Missing locale data for the locale "de-at".
With angular5 you have to load and register the used locale file on your own.
app.module.ts
import { NgModule, LOCALE_ID } from '#angular/core';
import { registerLocaleData } from '#angular/common';
import localeDeAt from '#angular/common/locales/de-at';
registerLocaleData(localeDeAt);
#NgModule({
providers: [
{ provide: LOCALE_ID, useValue: "de-at" }, //replace "de-at" with your locale
//otherProviders...
]
})
Documentation
If you use TranslateService from #ngx-translate/core, below is a version without creating a new pipe which works with switching dynamically on runtime (tested on Angular 7). Using DatePipe's locale parameter (docs):
First, declare the locales you use in your app, e.g. in app.component.ts:
import localeIt from '#angular/common/locales/it';
import localeEnGb from '#angular/common/locales/en-GB';
.
.
.
ngOnInit() {
registerLocaleData(localeIt, 'it-IT');
registerLocaleData(localeEnGb, 'en-GB');
}
Then, use your pipe dynamically:
myComponent.component.html
<span>{{ dueDate | date: 'shortDate' : '' : translateService.currentLang }}</span>
myComponent.component.ts
constructor(public translateService: TranslateService) { ... }
On app.module.ts add the following imports. There is a list of LOCALE options here.
import es from '#angular/common/locales/es';
import { registerLocaleData } from '#angular/common';
registerLocaleData(es);
Then add the provider
#NgModule({
providers: [
{ provide: LOCALE_ID, useValue: "es-ES" }, //your locale
]
})
Use pipes in html. Here is the angular documentation for this.
{{ dateObject | date: 'medium' }}
I've had a look in date_pipe.ts and it has two bits of info which are of interest.
near the top are the following two lines:
// TODO: move to a global configurable location along with other i18n components.
var defaultLocale: string = 'en-US';
Near the bottom is this line:
return DateFormatter.format(value, defaultLocale, pattern);
This suggests to me that the date pipe is currently hard-coded to be 'en-US'.
Please enlighten me if I am wrong.
I was struggling with the same issue and didn't work for me using this
{{dateObj | date:'ydM'}}
So, I've tried a workaround, not the best solution but it worked:
{{dateObj | date:'d'}}/{{dateObj | date:'M'}}/{{dateObj | date:'y'}}
I can always create a custom pipe.
You do something like this:
{{ dateObj | date:'shortDate' }}
or
{{ dateObj | date:'ddmmy' }}
See:
https://angular.io/docs/ts/latest/api/common/index/DatePipe-pipe.html
For those having problems with AOT, you need to do it a little differently with a useFactory:
export function getCulture() {
return 'fr-CA';
}
#NgModule({
providers: [
{ provide: LOCALE_ID, useFactory: getCulture },
//otherProviders...
]
})
Starting from Angular 9 localization process changed. Check out official doc.
Follow the steps below:
Add localization package if it's not there yet: ng add #angular/localize
As it's said in docs:
The Angular repository includes common locales. You can change your app's source locale for the build by setting the source locale in the sourceLocale field of your app's workspace configuration file (angular.json). The build process (described in Merge translations into the app in this guide) uses your app's angular.json file to automatically set the LOCALE_ID token and load the locale data.
so set locale in angular.json like this (list of available locales can be found here):
{
"$schema": "./node_modules/#angular/cli/lib/config/schema.json",
"version": 1,
"newProjectRoot": "projects",
"projects": {
"test-app": {
"root": "",
"sourceRoot": "src",
"projectType": "application",
"prefix": "app",
"i18n": {
"sourceLocale": "es"
},
....
"architect": {
"build": {
"builder": "#angular-devkit/build-angular:browser",
...
"configurations": {
"production": {
...
},
"ru": {
"localize": ["ru"]
},
"es": {
"localize": ["es"]
}
}
},
"serve": {
"builder": "#angular-devkit/build-angular:dev-server",
"options": {
"browserTarget": "test-app:build"
},
"configurations": {
"production": {
"browserTarget": "test-app:build:production"
},
"ru":{
"browserTarget": "test-app:build:ru"
},
"es": {
"browserTarget": "test-app:build:es"
}
}
},
...
}
},
...
"defaultProject": "test-app"
}
Basically you need to define sourceLocale in i18n section and add build configuration with specific locale like "localize": ["es"]. Optionally you can add it so serve section
Build app with specific locale using build or serve: ng serve --configuration=es
Above answers are certainly correct. Note that is is also possible to pass the locale with the pipe:
{{ now | date: undefined:undefined:'de-DE' }}
(The 2 first parameters being date format and timezone, leave them undefined if you are great with the defaults)
Not something you want to do for all your pipes, but sometimes it can be handy.
Copied the google pipe changed the locale and it works for my country it is posible they didnt finish it for all locales. Below is the code.
import {
isDate,
isNumber,
isPresent,
Date,
DateWrapper,
CONST,
isBlank,
FunctionWrapper
} from 'angular2/src/facade/lang';
import {DateFormatter} from 'angular2/src/facade/intl';
import {PipeTransform, WrappedValue, Pipe, Injectable} from 'angular2/core';
import {StringMapWrapper, ListWrapper} from 'angular2/src/facade/collection';
var defaultLocale: string = 'hr';
#CONST()
#Pipe({ name: 'mydate', pure: true })
#Injectable()
export class DatetimeTempPipe implements PipeTransform {
/** #internal */
static _ALIASES: { [key: string]: String } = {
'medium': 'yMMMdjms',
'short': 'yMdjm',
'fullDate': 'yMMMMEEEEd',
'longDate': 'yMMMMd',
'mediumDate': 'yMMMd',
'shortDate': 'yMd',
'mediumTime': 'jms',
'shortTime': 'jm'
};
transform(value: any, args: any[]): string {
if (isBlank(value)) return null;
if (!this.supports(value)) {
console.log("DOES NOT SUPPORT THIS DUEYE ERROR");
}
var pattern: string = isPresent(args) && args.length > 0 ? args[0] : 'mediumDate';
if (isNumber(value)) {
value = DateWrapper.fromMillis(value);
}
if (StringMapWrapper.contains(DatetimeTempPipe._ALIASES, pattern)) {
pattern = <string>StringMapWrapper.get(DatetimeTempPipe._ALIASES, pattern);
}
return DateFormatter.format(value, defaultLocale, pattern);
}
supports(obj: any): boolean { return isDate(obj) || isNumber(obj); }
}
Ok, I propose this solution, very simple, using ngx-translate
import { DatePipe } from '#angular/common';
import { Pipe, PipeTransform } from '#angular/core';
import { TranslateService } from '#ngx-translate/core';
#Pipe({
name: 'localizedDate',
pure: false
})
export class LocalizedDatePipe implements PipeTransform {
constructor(private translateService: TranslateService) {
}
transform(value: any): any {
const date = new Date(value);
const options = { weekday: 'long',
year: 'numeric',
month: 'long',
day: 'numeric',
hour: '2-digit',
minute: '2-digit',
second: '2-digit'
};
return date.toLocaleString(this.translateService.currentLang, options);
}
}
Using Pipes and No other installations.
LocalizedDatePipe.ts
import { Pipe, PipeTransform } from '#angular/core';
import { Locale } from 'src/app/contentful/interfaces/locale';
#Pipe({
name: 'localizedDate',
})
export class LocalizedDatePipe implements PipeTransform {
transform(value: any, locale: any): any {
const date = new Date(value);
const options: Intl.DateTimeFormatOptions = {
month: 'short',
day: 'numeric',
year: 'numeric',
};
return date.toLocaleDateString(locale, options);
}
}
Search-overlay.component.html
<span *ngIf="card.date" class="hero-cards-carousel__date">
{{ card.date | localizedDate: vm.locale?.code }}
</span>
Result
"20. Dez. 2012"
This might be a little bit late, but in my case (angular 6), I created a simple pipe on top of DatePipe, something like this:
private _regionSub: Subscription;
private _localeId: string;
constructor(private _datePipe: DatePipe, private _store: Store<any>) {
this._localeId = 'en-AU';
this._regionSub = this._store.pipe(select(selectLocaleId))
.subscribe((localeId: string) => {
this._localeId = localeId || 'en-AU';
});
}
ngOnDestroy() { // Unsubscribe }
transform(value: string | number, format?: string): string {
const dateFormat = format || getLocaleDateFormat(this._localeId, FormatWidth.Short);
return this._datePipe.transform(value, dateFormat, undefined, this._localeId);
}
May not be the best solution, but simple and works.

How to write console.log wrapper for Angular2 in Typescript?

Is there a way to write a global selfmade mylogger function that I could use in Angular2 typescript project for my services or components instead of console.log function ?
My desired result would be something like this:
mylogger.ts
function mylogger(msg){
console.log(msg);
};
user.service.ts
import 'commons/mylogger';
export class UserService{
loadUserData(){
mylogger('About to get something');
return 'something';
};
};
You could write this as a service and then use dependency injection to make the class available to your components.
import {Injectable, provide} from 'angular2/core';
// do whatever you want for logging here, add methods for log levels etc.
#Injectable()
export class MyLogger {
public log(logMsg:string) {
console.log(logMsg);
}
}
export var LOGGING_PROVIDERS:Provider[] = [
provide(MyLogger, {useClass: MyLogger}),
];
You'll want to place this in the top level injector of your application by adding it to the providers array of bootstrap.
import {LOGGING_PROVIDERS} from './mylogger';
bootstrap(App, [LOGGING_PROVIDERS])
.catch(err => console.error(err));
A super simple example here: http://plnkr.co/edit/7qnBU2HFAGgGxkULuZCz?p=preview
The example given by the accepted answer will print logs from the logger class, MyLogger, instead of from the class that is actually logging.
I have modified the provided example to get logs to be printed from the exact line that calls MyLogger.log(), for example:
get debug() {
return console.debug.bind(console);
}
get log() {
return console.log.bind(console);
}
I found how to do it here: https://github.com/angular/angular/issues/5458
Plunker: http://plnkr.co/edit/0ldN08?p=preview
As per the docs in developers.mozilla,
The bind() method creates a new function that, when called, has its
this keyword set to the provided value, with a given sequence of
arguments preceding any provided when the new function is called.
More information about bind here:
https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Function/bind
If you want to use 'console.log' function just in your component you can do this:
import { Component, OnInit } from '#angular/core';
var output = console.log;
#Component({
selector: 'app-component',
templateUrl: './app.component.html',
styleUrls: ['./app.component.scss']
})
export class AppComponent implements OnInit {
constructor() { }
ngOnInit() { }
printFunction(term: string): void {
output('foo');
}
}
How about using console on your main service, So we can customize and apply console.log conditionally:
myComponent.ts
export class myComponent implements OnInit {
constructor(
private config: GlobalService
) {}
ngOnInit() {
this.config.log('func name',{a:'aval'},'three');
}
}
global.service.ts
#Injectable()
export class GlobalService {
constructor() { }
this.prod = true;
public log(one: any, two?: any, three?: any, four?: any) {
if (!this.prod) {
console.log('%c'+one, 'background:red;color:#fff', two, three, four);
}
}
}
(Note: first parameter should be string in this example);
For toggling console.log ON\OFF:
logger.service.ts:
import { Injectable } from '#angular/core';
#Injectable()
export class LoggerService {
private oldConsoleLog = null;
enableLogger(){
if (this.oldConsoleLog == null) { return; }
window['console']['log'] = this.oldConsoleLog;
}
disableLogger() {
this.oldConsoleLog = console.log;
window['console']['log'] = function () { };
};
}
app.component.ts:
#Component({
selector: 'my-app',
template: `your templ;ate`
})
export class AppComponent {
constructor(private loggerService: LoggerService) {
var IS_PRODUCTION = true;
if ( IS_PRODUCTION ) {
console.log("LOGGER IS DISABBLED!!!");
loggerService.disableLogger();
}
}
}
I created a logger based on the provided information here
Its very basic (hacky :-) ) at the moment, but it keeps the line number
#Injectable()
export class LoggerProvider {
constructor() {
//inject what ever you want here
}
public getLogger(name: string) {
return {
get log() {
//Transform the arguments
//Color output as an example
let msg = '%c[' + name + ']';
for (let i = 0; i < arguments.length; i++) {
msg += arguments[i]
}
return console.log.bind(console, msg, 'color:blue');
}
}
}
}
Hope this helps
type safer(ish) version with angular 4, typescript 2.3
logger.service.ts
import { InjectionToken } from '#angular/core';
export type LoggerService = Pick<typeof console,
'debug' | 'error' | 'info' | 'log' | 'trace' | 'warn'>;
export const LOGGER_SERVICE = new InjectionToken('LOGGER_SERVICE');
export const ConsoleLoggerServiceProvider = { provide: LOGGER_SERVICE, useValue: console };
my.module.ts
// ...
#NgModule({
providers: [
ConsoleLoggerServiceProvider,
//...
],
// ...
my.service.ts
// ...
#Injectable()
export class MyService {
constructor(#Inject(LOGGER_SERVICE) log: LoggerService) {
//...
There is now an angular2 logger component on NPM which supports log levels.
https://www.npmjs.com/package/angular2-logger

Categories