1

I'm trying to implement inline editing using ngModel in Angular2. I have an array which needs to be iterated using ngFor and also uses ngModel. When i try to apply inline editing for this array, i can only edit one character for each of the array's variables.

You can find a working example here.

Here's the code for the component where i'm using ngModel and ngFor together:

import {Component} from '@angular/core'
import {InlineEditComponent} from './inline.component';
@Component({
  selector: 'inline-app',
  providers: [],
  template: `
    <div>
      <h2>Inline Editing with Angular 2</h2>
      <inline-edit [(ngModel)]="editableText" (onSave)="saveEditable($event)"></inline-edit>
    </div>
    <div>
      <ul style="margin:5px;">
      <li ngFor #arr [ngForOf]="array" [ngForTrackBy]="customTrackBy">
      <inline-edit [(ngModel)]="arr" (onSave)="saveEditable($event)"></inline-edit>
   </li>
        // <li style="margin:5px;" *ngFor="let arr of array ; let i=index">
        //   <inline-edit [(ngModel)]="array[i]" (onSave)="saveEditable($event)"></inline-edit>
        // </li>
      </ul>
    </div>
  `,
  directives: [InlineEditComponent]
})
export class InlineApp {
customTrackBy(index: number, obj: any): any {
    return index;
  }
  editableText = "Click to edit me!";
  // Save name to the server here.  
  saveEditable(value){
      console.log(value);
  }
  array=['bmw','benz','honda'];
}

If anyone could help me, it would be great.

3 Answers 3

2

You are editing the strings that are both immutable and direct elements of the array. That means whenever the string value changes, a new string object will be created and replace the old string in array, which in turn causes *ngFor to re-initiate new component for that string to replace the old one. If you put console.log('on-constructor') in the InlineEditComponent's constructor, you will see it's called every time you add a character.

To fix your problem, don't use string directly. Wrap them within a class like this:

export class Data {
  name: string;
}

then your array declaration will be:

array: Data[] = [
  {name:"bwm"},
  {name:"benz"},
  {name:"honda"}
];

With this, the changes will only affect name field, and wrapper objects are still the same; ngFor therefore will not be triggered to re-run.

Modified plnkr: https://plnkr.co/edit/WwGcLlisjGe1cmZOMHhD?p=preview

Sign up to request clarification or add additional context in comments.

4 Comments

I had thought that was what was going on with @Varun's problem... your solution is pretty good however the action of cancelling no longer cancels... it still saves any changes that were made
Yea I didn't do sanity check to all the other functions, should've put a warning there. My changes were purely to solve the problem he's having :)
In essence his solution involves making a model--the Data class. That's the recommended way to go when implementing any repeatable data object.
Thanks for the answer, but i posted a general answer which can be used for any list. The working code : plnkr.co/edit/7SSpZDec2N2zjrSUM04X?p=preview . @HarryNinh
0

You can bind directly to the array item instead of to the template variable:

<li *ngFor="let arr of array; let idx=index; ngForTrackBy:customTrackBy">
      <inline-edit [(ngModel)]="array[i]" (onSave)="saveEditable($event)"></inline-edit>

Btw: your ngFor syntax can only be used on <template> tags. If you use it on other elements the syntax used above is necessary.

See also https://angular.io/docs/ts/latest/guide/template-syntax.html#!#ngFor

Comments

0

This should be modified in the tamplate.

<ul>
            <li style="margin:5px;" *ngFor="let arr of array ; let i=index; trackBy:customTrackBy">
            <inline-edit [(ngModel)]="array[i]" (onSave)="saveEditable($event)"></inline-edit>
            </li>
</ul>

This functions should be added in the class:

export class{

customTrackBy(index: number): any {
    return index;
  }
}

The final working code:
https://plnkr.co/edit/7SSpZDec2N2zjrSUM04X?p=preview

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.