components: bug(material/chip): Mdc Chip Grid empties all options when using Reactive Forms and focusing out

Is this a regression?

  • Yes, this behavior used to work in the previous version

The previous version in which this bug was not present was

14.2.6

Description

Having Reactive forms attached to mat-chip-grid which accepts an array of object values, clears them on focus out.

Reproduction

Steps to reproduce:

  1. Create a formgroup with some formControl
  2. Bind it to <mat-chip-grid>
  3. Add some new options (or the same works if the list is already populated) that are arrays of objects.
  4. Focus out of the component

https://stackblitz.com/edit/angular-6g9jz1?file=src%2Fapp%2Fchips-input-example.ts,src%2Fapp%2Fchips-input-example.html

Upon further investigation, figured that the core problem is that on focus out, object values are transformed to strings hence why we don’t see the name property. Nevertheless objects were not transformed in v 14.

mat-grid-bug

Note: In the Docs Chip list works as expected because it is not bound to Reactive forms

Expected Behavior

All options remain with previously defined object values

Actual Behavior

All options are transformed to strings thus we have empty text options

Environment

  • Angular: 15.0.4
  • CDK/Material: 15.0.3
  • Browser(s): Chrome 108.0.5359.124
  • Operating System: macOS Ventura 13.1

About this issue

  • Original URL
  • State: open
  • Created a year ago
  • Reactions: 12
  • Comments: 17

Most upvoted comments

Ok, so I ran into the same issue as OP and luckily it looks like I was able to figure it out.

There’s a mistake in the template in the attached stackblitz example (the one from the starting post - just copying link here for convenience) which causes this issue (see picture below). [value] should be bound to option instead of option.name. Losing focus causes re-evaluation of the array which boils down to here - which ultimately causes array of objects to turn into an array of strings.

So, unless I missed something else, looks like there’s no bug here, just a little misunderstanding.

image

In my opinion, just defaulting to innerText is not a very good idea, and this thread is a very good example of why, especially the last issue reported by @poveu. I think this is not a bug in the sense that the code behaves as designed and doesn’t just break unexpectedly. The issue here is that the design itself is very confusing and unclear. I think the component should kick and scream at you if you don’t provide a value the way it expects it to be provided. Silent crippling the data without any explanations doesn’t seem acceptable to me.

Yeah… That’s an issue too albeit a different one. Mat components can’t really make any assumptions about the object being bound to the value property, hence they should ask app to provide some info/mappings/whatever it is about those objects, or they should clearly describe what assumptions mat components impose on those objects (like having certain field or something) in order for other functionality - like tag editing - to work correctly. This looks either like a missing functionality or a design flaw.

I suspect you can work around this particular issue by redefining .toString() in the tag objects but it feels more like a hack rather than a solution.

I think that since [value] appears to be from logical perspective, mandatory for <mat-chip-row>, and since we already have angular 16 in material, we can benefit from required inputs. The solution would be to make @Input({requred: true}) value in MatChip source code and at least catch some error in console. Also would be great if this information was documented. So I guess there are a couple of action points to be done.

That is very true @AlexanderLeonov & @jonastg ! Setting [value] param for mat-chip-row even fixes the issue I have reported a few posts above.

Looks like a breaking change that wasn’t reported in any clear way.

I’ll tell you something, the issue seems much bigger than that, as I have a case where your fix won’t help.

In some part of the application I’m using chips that display their name + description

<mat-chip-row
    *ngFor="let item of selectedItems"
    (removed)="remove(item)">
    <span class="chip-label">{{ item.name }}</span>
    <span class="chip-description">{{ item.description }}</span>
    <mat-icon matChipRemove>cancel</mat-icon>
</mat-chip-row>

image

As I have described previously, the focus out (blur) event causes the selected items array to become an array of strings. However, the bigger issue is that if I’m displaying name + description, then these two values get combined in the array, so the array (ngModel or control’s value) becomes: ['Google Chrome: Fast & Securecom.android.chrome']

Looks like the focus out event takes the innerText of the chip element and uses it as the item’s value, which seems like a huge misconception.