Leo
Leo

Reputation: 83

Pure pipe updating array in UI which is not supposed to happen

I was exploring Pipe functions in Angular and got to know that for non-primitive data types like arrays , even if there is a change in the array's elements the pipe function would not apply to the updated array and would be applied for the initial array itself. That is why when we add new elements pipe functions are not added to these new elements of the array.

But when I tried deleting, adding and updating existing elements of an array with a pipe function it worked. However, the changes the array should not be reflected to the UI as the pipe funciton is a pure one. Please let me know why the changes of an array are being reflected when the pipe is pure.

pipe.TS:

import { Pipe, PipeTransform } from '@angular/core';

@Pipe({
  name: 'arrayPipe',
  // pure:false
})
export class ArrayPipePipe implements PipeTransform {
  transform(value: number[]) {
    value.pop();
    value.push(4);
    value[1]=5;
    console.log(value);
    return (value);
  }
} 

app.HTML:

<div>{{trialArray}}</div>
<div>{{trialArray | arrayPipe }}</div>

app.component.TS:

import { Component } from '@angular/core';

@Component({
  selector: 'app-root',
  templateUrl: './app.component.html',
  styleUrls: ['./app.component.css']
})
export class AppComponent {

  trialArray = [1,2,3];
}

Upvotes: 0

Views: 505

Answers (1)

Eliseo
Eliseo

Reputation: 57939

question: When Angular know that "something" change?

answer: when his value change

The problem with arrays (and objects) are that not change when change some value (or some property) of it, else if change the "position in memory". This is the reason you need "create a new array". Generally you use the "spread operator"

this.trialArray=[...this.trialArray] //the ... are the spread operator

This is the reason because it's not a good aproach use pipe to transform an array (even a pipe sort)

In the stackblitz if you comment the line

this.trialArray=[...this.trialArray]

You can not see the array correctly

Of course you can create a pipe "impure". When you declare the pipe you write pure:false

@Pipe({
  name: 'arrayPipe',pure:false //<--see the "pure:false"
})
export class ArrayPipe implements PipeTransform{
   transform(value: any[], args?: any): any {
      return value.map((x) => x * 2);
   }
}

This makes that you can "change" the array (without create a copy) and show the result. But see that in this case the array in .html is not updated

<div>{{trialArray}}</div>  //<--this show always [1,2,3]
<div>{{trialArray | arrayPipe }}</div>  //<--this change when "click"

click(){
  this.trialArray.push(4);
}

but this makes that "In this case, the pipe is invoked on each change-detection cycle, even if the arguments have not changed.", see the docs.

We can see adding a console.log("here") in the function transform

About the pipe in the question there're two problems

  1. Change the value of the array. We can solve make a copy before (we can use the sprred operator

    export class ArrayPipe implements PipeTransform {
      transform(value: any[], args?: any): any {
        const result=[...value] //make a copy
        result.pop();   //change the copy
        result.push(4);
        result[1]=5;
        return result
      }
    }
    
  2. if we want we can convert the pipe to impure adding pure:false when create

Upvotes: 1

Related Questions