LoginSignup
24
17

ngModelで配列参照した時の悩み

Last updated at Posted at 2017-12-08

Angular Advent Calendar 2017 9日目の記事です。

私が働いている株式会社カケハシでは、Musubiというプロダクトを開発しており、そこにはAngularが使われています。

ちょっとあまり有用な情報ではないかもしれませんが、個人的にすごく悩んだ部分であるので、まとめて見ます。

悩み

例えば、以下のようなコードを書きます。

テンプレート側
<button (click)="addText()">add</button>
<div *ngFor="let text of texts;let i = index">
    <input [(ngModel)]="texts[i]">
</div>
typescript側
 private texts: string[] = ['test1', 'test2'];

  addText() {
    this.texts.push('');
  }

この時の出力は、

スクリーンショット 2017-12-03 12.16.23.png

のようになります。

ここで、inputに文字入力したいと思います。まずフォーカスを当てます。

スクリーンショット 2017-12-03 12.17.20.png

そして文字を入力します。すると…・

スクリーンショット 2017-12-03 12.17.53.png

フォーカスが外れてしまうのです。こいつは困った。

解決策1:配列を直接参照しないようにする

改善後
interface StringBox {
  text1: string;
}

@Component({
  selector: 'app-hello',
  templateUrl: './hello.component.html',
  styleUrls: ['./hello.component.css']
})
export class HelloComponent  {
  private texts: StringBox[] = [{text1: 'test1'}, {text1: 'test2'}];

  addText() {
    this.texts.push({text1: ''});
  }

}
テンプレート側
<button (click)="addText()">add</button>
<div *ngFor="let text of texts;let i = index">
    <input [(ngModel)]="texts[i].text1">
</div>

配列を直接参照しなければいいので、配列のメンバーを参照するとフォーカスが外れて連続で文字が入力できなくなる問題が解決します。
まあでもこの方法はいけてないですね。

解決策2:trackByを使う

改善後
@Component({
  selector: 'app-hello',
  templateUrl: './hello.component.html',
  styleUrls: ['./hello.component.css']
})
export class HelloComponent {
  private texts: string[] = ['test1', 'test2'];

  addText() {
    this.texts.push('');
  }

  myTrackBy(index: number, obj: any): any {
    return index;
  }

}
テンプレート側
<button (click)="addText()">add</button>
<div *ngFor="let text of texts;let i = index;trackBy: myTrackBy">
    <input [(ngModel)]="texts[i]">
</div>

これで解決します。

trackBy関数とは、ngForによるオブジェクトの追跡のためのキーを決める式です。
どうも文字を入力すると、Angularは今どの配列を参照しているかわからなくなり、フォーカスが外れてしまうのですが、
trackByでキーを教えてあげると、配列のどの位置を入力されているのがわかるようになり、そのまま入力できるようです。

これで解決できました。

24
17
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
24
17