Reputation: 69
I want to be able to control this component with the keyboard alone as much as possible. I do this by making sure you are pointed to the proper control on a tab press. On the last form field when you press tab it adds the temporary item to the list, resets the temporary item, and focuses you back on the first line item field.
The problem is if I want to have 2 line items with the same account, the second time I try to select it by pressing the first letter of the account name (in this case 'c') it skips an option because it was previously selected. I would like the options to reset when the temporary item is cleared.
To recreate the issue I'm trying to describe:
Enter any number for amount
Hit tab
Hit c (it will go to "Car Insurance")
Hit tab to submit the line and start at amount again
Enter an amount
Hit tab
and now if you try pressing 'c' again "Car Insurance" is no longer the first option. It defaults to the next item in the list for some reason.
I do not get the same issue if I use standard and tags, only when I use the material equivalents.
Here is the relevant code https://stackblitz.com/edit/angular-tab8tm
Upvotes: 2
Views: 1637
Reputation: 11081
Because you are technically still using the same mat-select
... and not creating a new one... the old value is still in the mat-select
...
There is a keyManager
behind the MatSelect
component managing all of this logic, and because you are pushing the current values into a new array and resetting the ngModel
... you will also need to reach into the keyManager
and default the values.
Create a templateRef
for the root mat-select
of #select
<mat-form-field class="temp-item-field" *ngIf="accounts">
<mat-select #select [(ngModel)]="tempItem.accountId" placeholder="Account">
<mat-option *ngFor="let account of accounts" [value]="account.id">{{account.name}}</mat-option>
</mat-select>
</mat-form-field>
Create @ViewChild
in component to get the reference
@ViewChild('select') _select
In your addItem()
set the activeItem
and activeItemIndex
to their default values.
addItem() {
if (this.tempItem.amount && this.tempItem.accountId) {
this.tempItem.transactionId = this.transaction.id;
this.transaction.transactionItems.push(this.tempItem);
this.tempItem = new TransactionItem();
this.focusTransactionAmount();
this._select['_keyManager']['_activeItem'] = undefined;
this._select['_keyManager']['_activeItemIndex'] = -1;
}
}
Stackblitz
https://stackblitz.com/edit/angular-ywrz7v?embed=1&file=src/app/app.component.ts
Personally I would recommend you explore using ReactiveForms
for this and generate your new fields via a FormControlArray
... instead of "shifting" your current values out of the current fields into new ones, and resetting the original root fields...
You could basically do the inverse of what you are doing now... create new fields with new formControls
and new state
on tab
leaving the current entered values where they are... and essentially be able to avoid this and using ngModel
all together.
Please see this SO answer where I provided a walk through of how the reactive forms work in an *ngFor
loop... along with stackblitz example.
The buildForm()
in the stackblitz would essentially be what you need to get your addItem()
pushing new formControls
which create new fields in the view automatically.
Dynamic form using *ngFor and submitting values from it
Upvotes: 1