2

I'm having troubles using a pipe in my reactive form. I have a pipe that transforms my object into an array so it can be used with *ngFor.

So far so good... the problem is that when I create an input (using form control to bind the value) inside my *ngFor, each change in this input triggers a pipe update. The result is that my input loses focus each time I write one letter in the input.

HTML:

<form [formGroup]="myForm" novalidate (ngSubmit)="save(myForm.value, myForm.valid)">
  <div *ngFor="let item of myForm.controls.object.value | keys" formGroupName='object'>
    <label>{{lang}}</label>
      <input name="item" type="text" placeholder="Option" [formControlName]="item.key"/>
  </div>
</form>

And my pipe:

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

@Pipe({
    name: 'keys'
})

export class KeysPipe implements PipeTransform {
    transform(value, args:string[]) : any {

        if (!value) {
            return value;
        }

        let keys = [];
        for (let key in value) {
            keys.push({key: key, value: value[key]});
        }
        return keys;
    }
}

Here is a plunker to demonstrate the issue.

How can I make the pipe inactive when I write or can I use a different approach than a pipe?

Please note that I can't change my object and that it has unkown properties (item1 and item2 in the plunker example)

Nate
  • 7,606
  • 23
  • 72
  • 124

1 Answers1

1

This might fix the issue

<div *ngFor="let item of myForm.controls.object.value | keys trackBy:trackByIdx" formGroupName='object'>
trackByIdx(index: number, obj: any): any {
  return index;
}

I think the problem is caused because *ngFor iterates over primitive values that are modified. *ngFor can't match the previous value with the new one and therefore removes the item and adds another one.

See also Angular2 NgFor inside tree model: wrong order when remove and then add elements

Community
  • 1
  • 1
Günter Zöchbauer
  • 623,577
  • 216
  • 2,003
  • 1,567
  • Amazing! There is a typo in `trackByIdy` (`trackByIdx`). BTW is there a way to directly use index (in the `trackBy`) instead of refering to an external function? – Nate Nov 27 '16 at 16:14
  • Don't think so. There is a pull request to allow to use a property name (of `item`) instead of a function but that doesn't work for primitive values. Another way around this would be to wrap the value in an object, then you don't need `trackBy` – Günter Zöchbauer Nov 27 '16 at 16:16