Skip to content

Commit 084241b

Browse files
committed
fix(material/chips): chips form control updating value immediately
Currently, when we have chips with form control, the value is updated only when its focused out. This fix will update the value of form control immediately Fixes angular#28065
1 parent 0bcbec0 commit 084241b

File tree

3 files changed

+86
-1
lines changed

3 files changed

+86
-1
lines changed

src/material/chips/chip-grid.spec.ts

+76
Original file line numberDiff line numberDiff line change
@@ -1013,6 +1013,48 @@ describe('MatChipGrid', () => {
10131013
}));
10141014
});
10151015

1016+
describe('chip with form control', () => {
1017+
let fixture: ComponentFixture<ChipsFormControlUpdate>;
1018+
let component: ChipsFormControlUpdate;
1019+
let nativeInput: HTMLInputElement;
1020+
let nativeButton: HTMLButtonElement;
1021+
let nativeChipGrid: HTMLElement;
1022+
1023+
beforeEach(() => {
1024+
fixture = createComponent(ChipsFormControlUpdate);
1025+
component = fixture.componentInstance;
1026+
1027+
nativeChipGrid = fixture.debugElement.query(By.css('mat-chip-grid'))!.nativeElement;
1028+
nativeInput = fixture.nativeElement.querySelector('input');
1029+
nativeButton = fixture.nativeElement.querySelector('button[id="save"]');
1030+
});
1031+
1032+
it('should update the form control value when pressed enter', fakeAsync(() => {
1033+
const nativeInput = fixture.nativeElement.querySelector('input');
1034+
nativeInput.value = 'hello';
1035+
nativeInput.focus();
1036+
fixture.detectChanges();
1037+
1038+
dispatchKeyboardEvent(document.activeElement!, 'keydown', ENTER);
1039+
fixture.detectChanges();
1040+
flush();
1041+
1042+
expect(component.keywordChipControl.value).not.toBeNull();
1043+
expect(component.keywordChipControl.value.length).toBe(1);
1044+
expect(nativeButton.disabled).toBeFalsy();
1045+
1046+
nativeInput.value = 'how are you ?';
1047+
nativeInput.focus();
1048+
fixture.detectChanges();
1049+
1050+
dispatchKeyboardEvent(document.activeElement!, 'keydown', ENTER);
1051+
fixture.detectChanges();
1052+
flush();
1053+
1054+
expect(component.keywordChipControl.value.length).toBe(2);
1055+
}));
1056+
});
1057+
10161058
function createComponent<T>(
10171059
component: Type<T>,
10181060
direction: Direction = 'ltr',
@@ -1218,3 +1260,37 @@ class ChipGridWithRemove {
12181260
this.chips.splice(event.chip.value, 1);
12191261
}
12201262
}
1263+
1264+
@Component({
1265+
template: `
1266+
<mat-form-field>
1267+
<mat-label>Keywords</mat-label>
1268+
<mat-chip-grid #chipGrid [formControl]="keywordChipControl">
1269+
@for (keyword of keywords; track keyword) {
1270+
<mat-chip-row>{{keyword}}</mat-chip-row>
1271+
}
1272+
</mat-chip-grid>
1273+
<input placeholder="New keyword..." [matChipInputFor]="chipGrid" (matChipInputTokenEnd)="add($event)">
1274+
</mat-form-field>
1275+
<button id="save" [disabled]="!keywordChipControl.valid">Save</button>
1276+
<button >Cancel</button>`,
1277+
standalone: false,
1278+
})
1279+
class ChipsFormControlUpdate {
1280+
public keywords = new Array<string>();
1281+
public keywordChipControl = new FormControl();
1282+
1283+
constructor() {
1284+
this.keywordChipControl.setValidators(Validators.required);
1285+
}
1286+
1287+
public add(event: MatChipInputEvent): void {
1288+
const value = (event.value || '').trim();
1289+
1290+
if (value) {
1291+
this.keywords.push(value);
1292+
}
1293+
1294+
event.chipInput.clear();
1295+
}
1296+
}

src/material/chips/chip-grid.ts

+8
Original file line numberDiff line numberDiff line change
@@ -415,6 +415,14 @@ export class MatChipGrid
415415
}
416416
}
417417

418+
_change() {
419+
// Timeout is needed to wait for the focus() event trigger on chip input.
420+
setTimeout(() => {
421+
this._propagateChanges();
422+
this._markAsTouched();
423+
});
424+
}
425+
418426
/**
419427
* Removes the `tabindex` from the chip grid and resets it back afterwards, allowing the
420428
* user to tab out of it. This prevents the grid from capturing focus and redirecting

src/material/chips/chip-input.ts

+2-1
Original file line numberDiff line numberDiff line change
@@ -198,7 +198,8 @@ export class MatChipInput implements MatChipTextControl, OnChanges, OnDestroy {
198198
value: this.inputElement.value,
199199
chipInput: this,
200200
});
201-
201+
this._chipGrid._change();
202+
this._chipGrid.stateChanges.next();
202203
event?.preventDefault();
203204
}
204205
}

0 commit comments

Comments
 (0)