Skip to content

Decorator for class functions to act like pure pipes in terms of update cycle, so can be used in component templates. #46135

@Phil-DS

Description

@Phil-DS

Which @angular/* package(s) are relevant/related to the feature request?

core

Description

If you have a function that gets an image url based on the inputs. Currently, you would either use a function or a pipe to map the data to a URL. For example, images representing items in a list view for fruits available at a supermarket. I know that, for the inputs, this function will always return the same URL for the fruit in question. An apple will always show an apple, a banana will be a banana, and same with a cherry. Currently, there doesn't seem to be a way to tell the change detector that it will always be the same based on inputs. Or, say, it's depending on internal values on a class. Let the change detection know it's directly correlated to certain inputs.

As a code example, I have the following class:

export class Fruit {
  fruit: string
  idFruit: number

  getFruitUrl() {
    // get me a pic of my fruit based on idFruit
  }
}

To use this in a component to render the output of transformResultToBeHumanReadable, you would either need to use a pipe that triggers the function, trigger this in a change event and cache the results on the component, or, use the function in the template, at the expense of being rendered multiple times. For multiple little things like this, you end up having to create multiple pipes or variables to cache the data. A declaration either via a function decorator or extended in the component decorator could potentially provide the update cycle with the knowledge of where the function updates, in order to not have to always update.

Proposed solution

Add a set of directives that allow functions to be recognised similar to pipes in terms of update cycle. There could even be bindings to tie update state to individual variables on the class.

export class Fruit {
  fruit: string
  idFruit: number

  @PureFunction({changesOn: [this.idFruit]})
  getFruitUrl() {
    // Only relies on idFruit, so only called when idFruit updates
  }

 @PureFunction()
  getFruitUrl(input: any) {
    // Only relies on input, so only changes if the values being input are different.
  }

  @PureFunction({changesOn: [this.idFruit]})
  getFruitUrl(large?: boolean) {
    // Only relies on both class variables and input variables, so changes when they do.
  }
}

or add declarations for the functions in the component declaration.

@Component({
  pureFunctions: [
    {name: "myFunc", changesOn: ["result"]}
  ]
}) class ObjComponent {
  result;
  myFunc() {

  }
}

Alternatives considered

While pipes were designed for this, excessive small pipes that are only needed in one or two places might not be as useful if we can just apply the pipe's change detection strategies to the function. An extension ChangeDetectionStrategy could be used to improve detecting changes if hints are given about how some functions handle change. Again, with the fruit idea, if it relies on only its inputs, and has an output that directly correlates to the input, and won't change its value outside of change detection, like an impure pipe, then it could be able to be considered like a pure Pipe.

Metadata

Metadata

Type

No type

Projects

No projects

Milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions