components icon indicating copy to clipboard operation
components copied to clipboard

mat-chip with autocomplete can add unwanted chips

Open aeslinger0 opened this issue 6 years ago • 12 comments

Bug, feature request, or proposal:

Bug

What is the expected behavior?

Typing a partial search term, using arrow keys to highlight option on autocomplete list, and pressing Enter should add only the selected chip.

What is the current behavior?

Intermittently, two chips are added. One for the selected value and one with the partial search term.

What are the steps to reproduce?

Providing a StackBlitz reproduction is the best way to share your issue.
StackBlitz starter: https://goo.gl/wwnhMV
I tried creating a StackBlitz to reproduce it, but couldn't get it to reproduce. Then I realized that it's a race condition causing it. More below...

What is the use-case or motivation for changing an existing behavior?

Addtional chip is unexpected behavior

Which versions of Angular, Material, OS, TypeScript, browsers are affected?

Angular/Material >= v6 for sure.

Is there anything else we should know?

The problem happens depending on the order that event handlers get executed. The code from the official example expects the optionSelected event of the mat-autocomplete to execute first (which clears out the input box), then for the matChipInputTokenEnd event of the input to execute (which avoids adding a chip if it's blank).

For whatever reason, using the exact same code and framework version in my app, the event handlers execute in the opposite order. Since the input hasn't been cleared yet, the search term gets added as an unexpected chip. Then the option from the autocomplete gets added as the expected chip.

aeslinger0 avatar Oct 11 '18 19:10 aeslinger0

Seconding this issue, I have noticed the same behavior here.

I did get Stackblitz to seemingly reproduce this issue here: https://stackblitz.com/edit/angular-yxkarc?embed=1&file=src/app/app.component.ts

Essentially what you say is the case, it will add both the currently selected value in the dropdown list as well as the partial search term you have in the autocomplete bar.

dreamstride avatar Oct 12 '18 13:10 dreamstride

@deadlymustard, I can reproduce it using your link. What did you change to get it to happen?

aeslinger0 avatar Oct 12 '18 13:10 aeslinger0

I generated a project locally with the latest version of Angular CLI using the default autocomplete example on the Angular docs (https://material.angular.io/components/chips/overview) and copied and pasted it over into a fresh Stackblitz project.

dreamstride avatar Oct 12 '18 14:10 dreamstride

You can fix this issue when you check the mat list for selected options. In the selected event you have to deselect the option. Only a workaround ^^

add(event: MatChipInputEvent): void { const input = event.input; const value = event.value; // Add our fruit if ((value || '').trim()&& // only add when no option selected !this.matAutocomplete.options.some((x) => x.selected === true)) { this.fruits.push(value.trim()); } // Reset the input value if (input) { input.value = ''; } this.fruitCtrl.setValue(null); }

selected(event: MatAutocompleteSelectedEvent): void { this.fruits.push(event.option.viewValue); this.fruitInput.nativeElement.value = ''; this.fruitCtrl.setValue(null); event.option.deselect(); // reset selected option }

alexfangmann avatar May 08 '20 07:05 alexfangmann

A work-around can be found here: https://github.com/angular/components/issues/19279#issuecomment-627263513

aeslinger0 avatar Jul 15 '20 11:07 aeslinger0

for what it's worth, I got this error today even after updating all my dependencies...

"@angular/animations": "~14.0.6", "@angular/cdk": "^14.0.5", "@angular/common": "~14.0.6", "@angular/compiler": "~14.0.6", "@angular/core": "~14.0.6", "@angular/forms": "~14.0.6", "@angular/material": "^14.0.5", "@angular/platform-browser": "~14.0.6", "@angular/platform-browser-dynamic": "~14.0.6", "@angular/router": "~14.0.6",

to fix it I just had to swap the order of the two imports to make sure selected(event: MatAutocompleteSelectedEvent) is called before remove(fruit: string):



  imports: [
SharedModule,
MatChipsModule,
MatAutocompleteModule,

],

imports: [
SharedModule,
MatAutocompleteModule,
MatChipsModule,

],

I tried to reproduce this by editing the example code and swapping the import order (https://stackblitz.com/run?file=src/app/chips-autocomplete-example.ts), however, I wasn't able to reproduce it. There are three potential reasons i could think of as to why it wouldn't reproduce, but I decided to leave it there. Potentially it's because stackblitz wasn't respecting the change of module import order, potentially it's because in the stackblitz example, the component example is the component that is bootstrapped and that affects how the modules are imported?, few other reasons. good luck.

robert-king avatar Jul 18 '22 21:07 robert-king

This problem is related to the order of the imports in module @deadlymustard when you change list of imports:

BrowserModule,
BrowserAnimationsModule,
MatFormFieldModule,
MatInputModule,
MatChipsModule,
MatIconModule,
FormsModule,
ReactiveFormsModule,
MatAutocompleteModule

to

BrowserModule,
BrowserAnimationsModule,
MatAutocompleteModule,
MatChipsModule,
MatFormFieldModule,
MatInputModule,
MatIconModule,
FormsModule,
ReactiveFormsModule

works like a charm,

example: https://stackblitz.com/edit/angular-fejzma?file=src%2Fapp%2Fapp.module.ts,src%2Fmaterial.module.ts

However, importing order should not cause such errors

Porkite avatar Sep 15 '22 11:09 Porkite

Oh Man! Thank ya! that behavior is just so weird. I lost almost an hour trying to find the solution and I never thought that was the order on the inputs! now it works smoothly! :D

onedapperterm avatar Sep 29 '22 11:09 onedapperterm

I spent a day on and off trying to find a reasonable explanation. When I gave up I started searching for nonsensical reasons, and stumbled on the solution here. I wouldn't have expected this to be allowed to happen in angular! The order of the handlers should be deterministic or at least manual!

To add a bit more clarity, the order of modules MatAutoCompleteModule and MatChipsModule is what decides, whether this bug occurs or not.

bahaabeih avatar Nov 25 '22 23:11 bahaabeih

I think it would be worth fixing the order of imports in the official example: https://material.angular.io/components/chips/overview#chips-autocomplete At least then not everyone using it as a starting point is stuck with this problem.

As I just started with Angular I've no idea what's possible or not. But I think it would be nice to emit a warning (console or terminal) if the order is wrong. That would save developers quite some time to debug this behavior.

mpflanzer avatar Sep 11 '23 08:09 mpflanzer

!this.matAutocomplete.options.some((x) => x.selected === true)) {

from where you get this.matAutocomplete?

its-dibo avatar Nov 24 '23 19:11 its-dibo

Why is there no full example where you can never add items that are not in the allFruits array, and use objects instead of strings. Real world examples would be so much better

rubenheymans avatar Apr 30 '24 20:04 rubenheymans