I'm learning Angular2 and I want to format a number adding thousand comma separator. As far as I have read this can be done using Pipes, the thing is that I want to format the number programmatically in the js file not in html (doing like var | number).
First of all I've realized there is no NumberPipe standalone pipe that I can work with (correct me if I'm wrong) the most similar one is CurrencyPipe in #angular2/common. So I have something like this:
import { Component } from '#angular/core';
import { CurrencyPipe } from '#angular/common';
#Component({
templateUrl: 'test.component.html',
styleUrls: ['./test.component.scss']
})
export class TestComponent {
public myNumber = 1000;
constructor(private currencyPipe: CurrencyPipe) {
var formatted = this.currencyPipe().transform(this.myNumber, 'MXN', true); // Is this correct?
}
}
But it throws me the following error:
Unhandled Promise rejection: No provider for CurrencyPipe! ; Zone: angular ;...
What am I doing wrong?
Thanks in advance.
Regards
First thing: you need to declare your pipe - add it to the NgModule declarations section:
declarations: [CurrencyPipe]
Second thing: pipes are not injectables, so you can't take its instance by using Angular dependency injection system. You need to create new instance of this pipe manually, like:
var formatted = (new CurrencyPipe()).transform(this.myNumber, 'MXN', true);
This actually works in an #Injectable display utility service with even less fuss than the previous answer involving modules. I imported my data model (below) and the pipe, then simply added the function. So, if you can't use the pipe directly in markup, use this trick!
export interface MoneyDTO extends SerializableDTO, JsonModelObjectDTO {
value?: string;
currency?: string;
}
import { CurrencyPipe } from '#angular/common';
formatMoney(money: MoneyDTO): string {
const cp: CurrencyPipe = new CurrencyPipe('en-US');
return money && money.value ? cp.transform(money.value, money.currency || 'USD', 'symbol') : null;
}
Related
I tried to start an angular project, I've created a simple component and started a console.log in it but I have Confusing problem. when I calling a function in html file from ts file its run twice
TS:
import { Component, OnInit } from '#angular/core';
#Component({
selector: 'app-hello',
templateUrl: './hello.component.html',
styleUrls: ['./hello.component.less']
})
export class HelloComponent implements OnInit {
constructor() { }
ngOnInit(): void {
}
log(val)
{
console.log(val);
}
test() {
let time = new Date()
console.log(time.getSeconds());
}
}
html :
hello works!
{{log('test')}}
{{test()}}
image log:
enter image description here
Where and how often do you call your component?
Can you produce a simple example on stackblitz?
Without any further info, we can just guess what it is.
You propably have called your component via '' twice.
Each instance will call all your template and hence its calling functions.
On my angular's component i'm using two methods from RxJs, debounceTime() and distinctUntilChanged()
import { Component, OnInit } from '#angular/core';
import { FormControl } from '#angular/forms';
import 'rxjs/add/operator/debounceTime';
import 'rxjs/add/operator/distinctUntilChanged';
#Component({
selector: 'app-form4th',
templateUrl: './form4th.component.html',
})
export class Form4thComponent implements OnInit {
searchField: FormControl;
searches: string[] = [];
constructor() { }
ngOnInit() {
this.searchField = new FormControl();
this.searchField
.valueChanges
.debounceTime(400)
.distinctUntilChanged()
.subscribe(term => {
this.searches.push(term);
});
}
}
App works fine, no error or even no warning message when doing (build) i.e. ng serve, and running the app on browser works as expected and no error message or warning too on browser console.
However, I have this weird TSLint message on my vscode saying:
[ts] Property 'debounceTime' does not exist on type 'Observable<any>'.
it's kind of annoying, since i kinda worry something doesn't work under the hood that i''m not aware of.
What am i missing here?
Thank You.
As explained in some comments, it's not a TSLINT error, it's a Typescript error.
The thing here, you're patching the prototype of Observable when you do that:
import 'rxjs/add/operator/debounceTime';
import 'rxjs/add/operator/distinctUntilChanged';
Instead of doing that, you might just want to take advantage of a new feature called lettable operators since rxjs v5.5. It let you use a new .pipe operator which takes functions as argument (rxjs operators or your own).
So instead of your code, try the following one:
import { Component, OnInit } from '#angular/core';
import { FormControl } from '#angular/forms';
// notice this import will not patch `Observable` prototype
import { debounceTime, distinctUntilChanged } from 'rxjs/operators';
#Component({
selector: 'app-form4th',
templateUrl: './form4th.component.html',
})
export class Form4thComponent implements OnInit {
searchField: FormControl;
searches: string[] = [];
constructor() { }
ngOnInit() {
this.searchField = new FormControl();
this.searchField
.valueChanges
.pipe(
debounceTime(400),
distinctUntilChanged()
)
.subscribe(term => {
this.searches.push(term);
});
}
}
By not patching the prototype of Observable it'll help your bundler to do tree shaking (if available) but I'm sure it'll be easier for Typescript to make the necessary checks as the functions will have to be imported in the same file. (that said, I've been using the old fashion method for a while and VSC was working as expected).
I'm currently getting started with Angular 2 and got stuck on something probably pretty simple:
I have a shared service chatMessageService.ts:
import { Injectable } from '#angular/core';
import { BehaviorSubject } from 'rxjs/BehaviorSubject';
#Injectable()
export class ChatMessageService {
private messageList = new BehaviorSubject<string>("");
currentMessage = this.messageList.asObservable();
constructor() {
}
public addMessage(msg:string) {
this.messageList.next(msg) }
}
The service is imported by two components, one that calls it's addMessage function to add the message to the Observable and then my chatComponent.ts looks like this (shortened fpr convinience):
import { Component } from '#angular/core';
import { Message } from './message';
import { ChatMessageService } from './chatMessage.service';
#Component({
selector: 'app-chat',
templateUrl: './chat.component.html',
styleUrls: ['./chat.component.css']
})
export class ChatComponent {
conversation: Message[] = [];
//.....
constructor(private chatMessageService: ChatMessageService) { }
addUserMessage(message) {
this.conversation.push({
content: message
});
}
ngOnInit() {
this.chatMessageService.currentMessage.subscribe(message => {this.addUserMessage(message);} )
}
}
My crisis arises at that last subscripion part. When I replace
{this.addUserMessage(message);}
with
{console.log(message)}
the message is printed out perfectly fine. If I call the addUserMessage()-method manually it works just fine. But when I call the method right there, with the message as argument, nothing happens. The method isn't even executed?
Thankful for your insights!
It looks like you need some buffering in the service.
Instead of BehaviorSubject, try
private messageList = new ReplaySubject<string>(10);
See working example: Plunker
I have a ShareService in angular 2,
******************************shareService*************************
import { BehaviorSubject , Subject} from 'rxjs/Rx';
import { Injectable } from '#angular/core';
#Injectable()
export class shareService {
isLogin$:BehaviorSubject<boolean> = new BehaviorSubject<boolean>(false);
CheckUser = this.isLogin$.asObservable();
public isLogin (bool){
this.isLogin$.next(bool);
}
}
and its my another component and subscibe the CheckUser;
***********************another Component*******************************
_shareService.CheckUser.subscribe((val) =>{
*********all of this scope execute for several times just i have one another component and one next function*******
this.isLogin = val;
alert(val);
if(this.isLogin){
console.log("req req req");
this.MyBasket();
}
else if(this.ext.CheckLocalStorage("ShopItems")){
this.ShopItems = JSON.parse(localStorage.getItem("ShopItems"));
setTimeout(() => {
_shareService.sendShopItems(this.ShopItems);
},100);
}
});
my problem is i execute once this.isLogin$.next(bool) but subscribe function execute twice or several times !!!! my basket function is an xhr request this means when user loged in i get the several request to server!!!i cant fix it...i dont know this problem is for angular 2 or not,Anyone have this problem??
last a few days i Involved in this problem!
The problem is that your shareService is getting multiple instances.
One of the solutions is forcing the service to be a singleton.
Something like this should work:
import { provide, Injectable } from '#angular/core';
#Injectable()
export class shareService {
private static instance: shareService = null;
// Return the instance of the service
public static getInstance(/*Constructor args*/): shareService {
if (shareService.instance === null) {
shareService.instance = new shareService(/*Constructor args*/);
}
return shareService.instance;
}
constructor(/*Constructor args*/) {}
}
export const SHARE_SERVICE_PROVIDER = [
provide(shareService, {
deps: [/*Constructor args dependencies*/],
useFactory: (/*Constructor args*/): shareService => {
return shareService.getInstance(/*Constructor args*/);
}
})
];
Everything that is required on your current constructor should be placed where it says constructor args
Now on your components you use the service like this:
#Component({
providers: [SHARE_SERVICE_PROVIDER]
})
And then you can call it like you usually do.
Another solution would be injecting your current service on the main component of the app. See here for more info.
The problem is that the service is singleton and the component subscribe to it each time it created or (I don't see the full code) at the point the
_shareService.CheckUser.subscribe
is placed , so CheckUser should be a method that returns an Observable . if you have plunkr I can edit it .
Another semantic problem is that the observable should end with $ and not the BehaviorSubject.
I'm trying to play with Angular 2-beta and I want to work with Http component. But there is a serious problem here:
I read this and
I know in Angular 2(Unlike Angular 1), Http component is not a service that returns a Promise. It returns something called Observable. We know that a Component is better not to use Http directly. Efficient way is to make a service that is responsible to consume Http. But how?! Should this after completing a request, return a promise? (look at here)
Does it make sense at all?!
It's possible with Angular 2 to implement services. They simply correspond to injectable classes as described below. In this case this class can be injected into other elements like components.
import {Injectable} from 'angular2/core';
import {Http, Headers} from 'angular2/http';
import 'rxjs/add/operator/map';
#Injectable()
export class CompanyService {
constructor(http:Http) {
this.http = http;
}
}
You can inject an Http object in it (using its constructor) at the condition you specified HTTP_PROVIDERS when bootstraping the main component of your application:
import {bootstrap} from 'angular2/platform/browser'
import {HTTP_PROVIDERS} from 'angular2/http';
import {AppComponent} from './app.component'
bootstrap(AppComponent, [
HTTP_PROVIDERS
]);
This service can be then injected into a component, as described below. Don't forget to specify it within the providers list of the component.
import { Component, View, Inject } from 'angular2/core';
import { CompanyService } from './company-service';
#Component({
selector: 'company-list',
providers: [ CompanyService ],
template: `
(...) `
})
export class CompanyList {
constructor(private service: CompanyService) {
this.service = service;
}
}
You can then implement a method leveraging the Http object in your service and return the Observable object corresponding to your request:
#Injectable()
export class CompanyService {
constructor(http:Http) {
this.http = http;
}
getCompanies() {
return this.http.get('https://angular2.apispark.net/v1/companies/')
.map(res => res.json());
}
}
The component can then call this getCompanies method and subscribe a callback on the Observable object to be notify when the response is there to update the state of the component (in the same way you did with promises in Angular1):
export class CompanyList implements OnInit {
public companies: Company[];
constructor(private service: CompanyService) {
this.service = service;
}
ngOnInit() {
this.service.getCompanies().subscribe(
data => this.companies = data);
}
}
Edit
As foxx suggested in his comment, the async pipe could be also used to implicitly subscribe on the observable object. Here is the way to use it. First update your component to put the observable object in the attribute you want to display:
export class CompanyList implements OnInit {
public companies: Company[];
constructor(private service: CompanyService) {
this.service = service;
}
ngOnInit() {
this.companies = this.service.getCompanies();
}
}
Use then the async pipe in your template:
#Component({
selector: 'company-list',
providers: [ CompanyService ],
template: `
<ul>
<li *ngFor="#company of companies | async">{{company.name}}</li>
</ul>
`
})
export class CompanyList implements OnInit {
(...)
}
This article in two parts could give more details as well:
http://restlet.com/blog/2015/12/30/implementing-an-angular-2-frontend-over-an-apispark-hosted-web-api-part-1/
http://restlet.com/blog/2016/01/06/implementing-an-angular-2-frontend-over-an-apispark-hosted-web-api-part-2/
Hope it helps you,
Thierry
There is no need to convert the observable returned by Http's get() method into a promise. In most cases, the service can simply return the observable.
If we are fetching an array or a primitive type (i.e., string, number, boolean) from the server, we can simplify our controller logic by using the returned observable directly in our template, with the asyncPipe. This pipe will automatically subscribe to the observable (it also works with a promise) and it will return the most recent value that the observable has emitted. When a new value is emitted, the pipe marks the component to be checked for changes, hence the view will automatically update with the new value.
If we are fetching an object from the server, I'm not aware of any way to use asyncPipe, we could use the async pipe, in conjunction with the safe navigation operator as follows:
{{(objectData$ | async)?.name}}
But that looks complicated, and we'd have to repeat that for each object property we wanted to display.
Instead, I suggest we subscribe() to the observable in the component and store the contained object into a component property. We then use the safe navigation operator (?.) or (as #Evan Plaice mentioned in a comment) NgIf in the template. If we don't use the safe navigation operator or NgIf, an error will be thrown when the template first tries to render, because the object is not yet populated with a value.
Note how the service below always returns an observable for each of the get methods.
service.ts
import {Injectable} from 'angular2/core';
import {Http} from 'angular2/http';
import 'rxjs/add/operator/map'; // we need to import this now
#Injectable()
export class MyService {
constructor(private _http:Http) {}
getArrayDataObservable() {
return this._http.get('./data/array.json')
.map(data => data.json());
}
getPrimitiveDataObservable() {
return this._http.get('./data/primitive.txt')
.map(data => data.text()); // note .text() here
}
getObjectDataObservable() {
return this._http.get('./data/object.json')
.map(data => data.json());
}
}
app.ts
import {Component} from 'angular2/core';
import {MyService} from './my-service.service';
import {HTTP_PROVIDERS} from 'angular2/http';
#Component({
selector: 'my-app',
providers: [HTTP_PROVIDERS, MyService],
template: `
<div>array data using '| async':
<div *ngFor="#item of arrayData$ | async">{{item}}</div>
</div>
<div>primitive data using '| async': {{primitiveData$ | async}}</div>
<div>object data using ?.: {{objectData?.name}}</div>
<div *ngIf="objectData">object data using NgIf: {{objectData.name}}</div>`
})
export class AppComponent {
constructor(private _myService:MyService) { console.clear(); }
ngOnInit() {
this.arrayData$ = this._myService.getArrayDataObservable();
this.primitiveData$ = this._myService.getPrimitiveDataObservable();
this._myService.getObjectDataObservable()
.subscribe(data => this.objectData = data);
}
}
Note: I put "Observable" in the service method names – e.g., getArrayDataObervable() – just to highlight that the method returns an Observable. Normally you won't put "Observable" in the name.
data/array.json
[ 1,2,3 ]
data/primitive.json
Greetings SO friends!
data/object.json
{ "name": "Mark" }
Output:
array data using '| async':
1
2
3
primitive data using '| async': Greetings SO friends!
object data using .?: Mark
object data using NgIf: Mark
Plunker
One drawback with using the async pipe is that there is no mechanism to handle server errors in the component. I answered another question that explains how to catch such errors in the component, but we always need to use subscribe() in this case.