Reputation: 307
I have a very simple component that makes a nice little dashboard card and I can reuse it for multiple pieces of data. When I use test data, my condition works great, as it sends the data immediately and picks the correct pipe. However, on the real dashboard it calls for the data from an API. The data is returned but since this is no longer in the ngOnInit, my condition doesn't fire. Would anyone know how I might pick the right condition after getting data back from my service?
Component:
import { Component, OnInit } from '@angular/core';
import {SecondsToMinutesPipe} from "../seconds-to-minutes.pipe";
import { DecimalPipe } from "@angular/common";
@Component({
selector: 'app-dash-stat',
inputs: [
'icon', 'color', 'amount', 'description', 'time'
],
templateUrl: './dash-stat.component.html',
styleUrls: ['./dash-stat.component.css'],
})
export class DashStatComponent implements OnInit {
private loading: boolean = true;
private icon: string;
private color: string = '#fff';
private amount: any = 0;
private description: string;
private time: boolean = false;
constructor(private timePipe: SecondsToMinutesPipe, private numberPipe: DecimalPipe) { }
ngOnInit() {
this.loading = false; //remove this and figure out
if(this.time){
this.amount = this.timePipe.transform(this.amount);
}
else
{
this.amount = this.numberPipe.transform(this.amount, '1.0-0');
}
}
}
And I call it from my dashboard like this:
<div class="col-sm">
<app-dash-stat icon="fa-tint" color="#eb1c2d" description="Litres Flown" amount="{{dashStats.volume}}"></app-dash-stat>
</div>
<div class="col-sm">
<app-dash-stat icon="fa-clock-o" color="#fd6b00" description="Average Loading Time" amount="{{dashStats.filltime}}" time="true"></app-dash-stat>
</div>
Upvotes: 0
Views: 1283
Reputation: 962
If you want to pass data from one component to the other and this data kind of changes, you wanna create an injectable data service you can subscribe to that can pass the value around. This is a copy of my data service, to give you an idea:
import { Injectable } from '@angular/core';
import { Observable } from 'rxjs/Rx';
import { ReplaySubject } from 'rxjs/ReplaySubject';
@Injectable()
export class DataService {
// for single non-async string data
stringData: string;
// for complex async data; use setData/getData
private dataItem: ReplaySubject<any> = new ReplaySubject<any>();
public setData(data: any) {
this.dataItem.next(data);
};
public getData(): Observable<any> {
return this.dataItem.asObservable();
};
}
In your app.module.ts you import it and add it the @NgModule
providers:
import { DataService } from '../app/Services/data.service';
@NgModule({
...
providers: [
DataService
]
...
Then in both your components you import it:
import { DataService } from '../Services/data.service';
And you use it in the components like so:
Source component:
export class sourceComponent {
myVariable: any;
constructor(
public dataService: DataService){
// do something...
}
SomeFunction(): void {
// do something...
this.dataService.setData(this.myVariable);
}
}
Target component:
import { Subscription } from "rxjs/Subscription";
// @component and stuff...
export class targetComponent {
myValue: any;
subscription: Subscription;
constructor(
public dataService: DataService) {
this.subscription = this.dataService.getData()
.subscribe(
data => {
this.myValue = data;
// do stuff maybe
},
error => {
console.log(error);
});
}
}
Then the data should update every time something happens. So that you don't get memory leaks, be sure to unsubscribe in the target component like so:
ngOnDestroy() {
// unsubscribe to ensure no memory leaks
this.subscription.unsubscribe();
}
Upvotes: 2
Reputation: 307
I was thinking maybe emitting events would work, but ngOnChanges ended up doing the trick.
ngOnChanges(changes: SimpleChanges){
this.loading = false; //remove this and figure out
if(this.time){
this.amount = this.timePipe.transform(changes.amount.currentValue);
}
else
{
this.amount = this.numberPipe.transform(changes.amount.currentValue, '1.0-0');
}
}
Upvotes: 0
Reputation: 463
First, if you think <app-dash-stat icon="fa-tint" color="#eb1c2d" description="Litres Flown" amount="{{dashStats.volume}}"></app-dash-stat>
this syntax would pass data to the <app-dash-stat>
component that is wrong. The code is syntactically wrong. You cannot simply call attributes like this. You should enclose them with [ ]
.
<app-dash-stat icon="fa-tint" [color]="#eb1c2d" [description]="Litres Flown" [amount]="dashStats.volume">
and you cannot mix property binding and interpolation.
And in your class the variables that need data to be injected from the parent component, you should use the @Input()
annotation.
@Input() private loading: boolean = true;
@Input() private icon: string;
@Input() private color: string = '#fff';
@Input() private amount: any = 0;
@Input() private description: string;
@Input() private time: boolean = false;
Upvotes: 0