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>
private texts: string[] = ['test1', 'test2'];
addText() {
this.texts.push('');
}
この時の出力は、
のようになります。
ここで、inputに文字入力したいと思います。まずフォーカスを当てます。
そして文字を入力します。すると…・
フォーカスが外れてしまうのです。こいつは困った。
解決策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でキーを教えてあげると、配列のどの位置を入力されているのがわかるようになり、そのまま入力できるようです。
これで解決できました。