Angular 2 pipe with variable parameter
Solution 1
Pipe:
@Pipe(name: 'tempConverter')
export class TemperatureConverterPipe implements PipeTransform {
// Selected temperature unit
//private unit: string;
constructor(){
}
// Return temperature
transform(value: number,unit:string): number {
switch(unit){
case "c":
return value;
break;
case "f":
return celsiusToFahrenheit(value);
break;
default:
return value;
}
}
// Convert celsius temp to fahrenheit
celsiusToFahrenheit(value: number){
return value * 9/5 + 32;
}
}
HTML call:
[temperatureProperty]="value | tempConverter:unit"
Subscribe to the service in the ngOninit of calling component and pass unit.
Solution 2
You can make the pipe impure
@Pipe(name: 'tempConvert', pure: false)
export class TemperatureConverterPipe ...
this way the pipe is called every time change detection is run. With impure pipes you should ensure that the pipe doesn't do any expensive work because it will be called very often.
Admin
Updated on June 23, 2022Comments
-
Admin almost 2 years
I'm in the course of learning Angular2/Ionic2 so please excuse my ignorance. I got to learning Pipes and everything seemed easy until I stumbled on this problem. Let me demonstrate the problem using a perfect example with temperatures.
Say that I have pipe which return Celisus or Fahrenheit temperature value, depending on the setting saved on localStorage (Celsius is default input value).
So I created a Pipe which do this:
export class TemperatureConverterPipe implements PipeTransform { // Selected temperature unit private unit: string; constructor(private settings: Settings){ // Get immediately the temperature unit from localStorage // And subscribe to changes this.settings.radio().subscribe(data => { this.unit = data.temp_unit }); } // Return temperature transform(value: number): number { switch(this.unit){ case "c": return value; break; case "f": return celsiusToFahrenheit(value); break; default: return value; } } // Convert celsius temp to fahrenheit celsiusToFahrenheit(value: number){ return value * 9/5 + 32; } }
Problems I'm stuck at:
- How this pipe can watch for parameter change (Temperature unit) and return the new values (e.q. C to F)? Because currently it only watches for Input (Temperature value) changes.
- Is this a correct way to solve this?
Thank you very much!
-
Poul Kruijt over 7 yearsDarn, I'm facing a 'problem' as well, where I do not want to use an impure pipe, but still want to be able to force a refresh on a pipe, because a client setting has changed. Now this is still a non expensive pipe, but I can imagine that there will be situations where it will be. Do you know if they are going to implement something in the near future? A force refresh on a certain pipe :) (i know this doesn't belong here in the comments, but hey, we are wearing cool hats)
-
Günter Zöchbauer over 7 yearsAn alternative way is to pass a parameter that changes, like
[prop]="value | myPipe:dummyCounter". Whenever
dummyCounter` changes, the pipe will be called. I wouldn't expect changes to be made to the pipe implementation in the near future. -
Admin over 7 yearsI forgot to mention a tried creating an impure pipe, the problem is I think this is not the best solution. Can't I just manually invoke recalculating values on unit change?
-
Günter Zöchbauer over 7 yearsNo, the only ways are the value or parameters changing (for pure pipes) or change detection being run (for impure pipes). You can use
ChangeDetectionStrategy.OnPush
and detach the change detector in your component to limit the number of times change detection is run to limit performance impact when using impure pipes (this is a good idea anyway no matter if you use impure pipes or not). -
Admin over 7 yearsYour way worked perfectly fine, but I can't belive how complex it is to solve such a simple task. Anyway thank you Suraj, you just made my day much better.