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('');
}
この時の出力は、
![スクリーンショット 2017-12-03 12.16.23.png](https://qiita-user-contents.imgix.net/https%3A%2F%2Fqiita-image-store.s3.amazonaws.com%2F0%2F4044%2F9ee6f495-a90e-89b3-0e55-2af3e7bf770d.png?ixlib=rb-4.0.0&auto=format&gif-q=60&q=75&s=46b3f0ffb25f60b5036d5d24ace35ea6)
のようになります。
ここで、inputに文字入力したいと思います。まずフォーカスを当てます。
![スクリーンショット 2017-12-03 12.17.20.png](https://qiita-user-contents.imgix.net/https%3A%2F%2Fqiita-image-store.s3.amazonaws.com%2F0%2F4044%2F94493977-2175-ee53-abee-6ac60589a09f.png?ixlib=rb-4.0.0&auto=format&gif-q=60&q=75&s=0f9a376317a9640ca90c9a09d0978152)
そして文字を入力します。すると…・
![スクリーンショット 2017-12-03 12.17.53.png](https://qiita-user-contents.imgix.net/https%3A%2F%2Fqiita-image-store.s3.amazonaws.com%2F0%2F4044%2Ff3c483bd-62a7-b5f8-bd7d-7b2fbe40e358.png?ixlib=rb-4.0.0&auto=format&gif-q=60&q=75&s=927fbffd4594fa245aea794809c95bd7)
フォーカスが外れてしまうのです。こいつは困った。
解決策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でキーを教えてあげると、配列のどの位置を入力されているのがわかるようになり、そのまま入力できるようです。
これで解決できました。