Signal Forms: [formField] bound to a CVA control (e.g. mat-chip-listbox) crashes with "this.field(...) is not a function" on a native double-click
Chưa có ai nhận issue này.
Đánh giá
- Độ khó
- 4/5
- Thời gian dự kiến
- 3-5 ngày
- Mức phù hợp với người mới
- 48/100
- Loại issue
- Lỗi
- Độ rõ ràng
- Khá rõ ràng
- Mức độ hoạt động
- Sôi nổi
- Công nghệ
- angular, typescript
- Lĩnh vực
- frontend
Hướng nghiên cứu
Bắt đầu với bản tái hiện tối thiểu được liên kết và tái hiện lỗi nhấp đúp đồng bộ, sau đó kiểm tra stack @angular/forms/signals xung quanh FormField.state và ɵngControlUpdate, so sánh một lần nhấp với hai lần nhấp trong cùng một lượt thông qua cầu nối ControlValueAccessor. Được xem là hoàn tất khi bản tái hiện không còn báo TypeError hoặc NG01902 và mat-chip-listbox được liên kết vẫn sử dụng được khi nhấp nhiều lần.
Do mô hình lập chỉ mục viết ra từ nội dung của issue.
Mô tả
Which @angular/* package(s) are the source of the bug?
forms
Is this a regression?
No
Description
Binding [formField] to a component that Signal Forms integrates via the ControlValueAccessor bridge (e.g. mat-chip-listbox) crashes with TypeError: this.field(...) is not a function when two click events fire synchronously in the same JS turn - which is exactly what a native double-click produces (browsers dispatch two click events before dblclick).
This is not specific to a dynamic/record-keyed field - it reproduces with a single, plain, statically-named field on a minimal one-field form. It also surfaces the related error NG01902: Orphan field, looking for property '<key>' of <root> on the same trigger.
Reproduced two ways:
el.click(); el.click();on the chip option, in the same script turn (no animation/timing involved)- Playwright's
.dblclick()
A debounce() on the field does not prevent it (tested both applied and unset).
Minimal reproduction
import { Component, signal } from '@angular/core';
import { bootstrapApplication } from '@angular/platform-browser';
import { form, FormField } from '@angular/forms/signals';
import { provideAnimationsAsync } from '@angular/platform-browser/animations/async';
import { MatChipsModule } from '@angular/material/chips';
interface Model {
color: string;
}
@Component({
selector: 'app-root',
standalone: true,
imports: [FormField, MatChipsModule],
template: `
<mat-chip-listbox [formField]="colorForm.color">
<mat-chip-option value="red">Red</mat-chip-option>
<mat-chip-option value="blue">Blue</mat-chip-option>
</mat-chip-listbox>
`,
})
export class App {
model = signal<Model>({ color: '' });
colorForm = form(this.model);
}
bootstrapApplication(App, { providers: [provideAnimationsAsync()] });
Steps:
- Load the page.
- Double-click either chip option (or, via devtools console:
document.querySelector('mat-chip-option').click(); document.querySelector('mat-chip-option').click();).
Verified locally against exactly this minimal component (isolated from any larger app code) with both trigger methods above - 0 errors on a single click, crashes reliably on every double-click / synchronous double-click().
Please provide a link to a minimal reproduction of the bug
https://github.com/CSchulz/angular-signal-forms-dblclick-repro
Please provide the exception or error you saw
ERROR TypeError: this.field(...) is not a function
at FormField.state.ngDevMode.debugName [as computation] (@angular_forms_signals.js:3109:38)
at Object.producerRecomputeValue (chunk-....js:300:25)
at producerUpdateValueVersion (chunk-....js:110:8)
at _FormField.computed2 [as state] (chunk-....js:263:5)
at _FormField.ɵngControlUpdate (@angular_forms_signals.js:2910:31)
at Object.update (chunk-....js:10664:33)
at controlUpdateInternal (chunk-....js:8546:14)
at Module.ɵɵcontrol (chunk-....js:8532:3)
and, on repeated triggering:
RuntimeError: NG01902: Orphan field, looking for property 'color' of <root>.
Please provide the environment you discovered this bug in (run ng version)
Angular CLI: 22.0.6
Angular: 22.0.6
@angular/material: 22.0.4
@angular/cdk: 22.0.4
Node.js: 24.15.0
TypeScript: 6.0.3
rxjs: 7.8.2
Anything else?
Re-verified 2026-08-19 against:
- 22.2.0-next.2/22.2.0-next.3 (
nextdist-tag, i.e. the newest prerelease, not yet promoted tolatest) - same crash, not fixed there either - Also reproduces with
provideNoopAnimations()instead ofprovideAnimationsAsync()- not animation-timing-related
Is mat-chip-listbox required, or would any CVA control do?
Every frame in the stack trace above is @angular/forms/signals code - no @angular/material code appears in it, so the defect itself is squarely in Signal Forms. That said, a hand-written, Material-free ControlValueAccessor component (tried both a plain two-<button> version and a more faithful one with nested child components, ChangeDetectorRef.markForCheck(), and an
EventEmitter) does not reproduce the crash under the same conditions (page.dblclick() on a never-before-clicked element). So mat-chip-listbox isn't strictly required, but something about its specific interaction pattern is a necessary trigger for this repro, and that trigger has not been identified yet - this app has no zone.js dependency (it's zoneless), which already rules out one candidate (CDK's FocusMonitor/MatRipple moving work in and out of NgZone, since without zone.js those calls are inert no-ops).
Additional context
- We first hit this in an app with a dynamic per-key record model bound via
[formField]="form[dynamicKey]"to amat-chip-listboxinside an@forloop - but the minimal repro above shows the dynamic-key/loop aspect isn't required at all; a single static field on a single-field form is enough. - Workaround: bind the CVA-based control manually (
[value]/(change)reading and writingfield().valuedirectly) instead of[formField], bypassing the affected path entirely - at the cost of losing automatictouched/disabled/focus wiring for that control.
- Ngôn ngữ chính
- TypeScript
- Star
- 25k
- Fork
- 6.8k
- Merge trung bình
- 1 ngày 1 giờ
- Pull request đã merge (30 ngày)
- 84
Hướng dẫn đóng góp
Bắt đầu từ đâu
- Đọc hết issue, rồi đọc hướng dẫn đóng góp của dự án.
- Bình luận trên issue rằng bạn sẽ nhận — tránh hai người làm cùng một việc.
- Fork repository và làm thay đổi trên một nhánh.
- Mở pull request có tham chiếu số hiệu của issue.
Issue khác của angular/components
-
area: material/tree docs gemini-triaged needs triage
Độ khó 2/5 1-3 giờ Mức phù hợp với người mới 68/100
angular/components#33832 ·
-
area: material/datepicker gemini-triaged P4
Độ khó 2/5 1-3 giờ Mức phù hợp với người mới 72/100
angular/components#33763 · 2 bình luận · 3 reaction ·
-
area: material/table gemini-triaged P4
Độ khó 1/5 Dưới một giờ Mức phù hợp với người mới 88/100
angular/components#33709 · 1 bình luận ·
-
area: material/table docs gemini-triaged P4
Độ khó 2/5 1-3 giờ Mức phù hợp với người mới 72/100
angular/components#33455 ·
-
area: material/core gemini-triaged P3
Độ khó 1/5 Dưới một giờ Mức phù hợp với người mới 78/100
angular/components#33059 · 2 bình luận ·
Tất cả issue của angular/components
Issue tương tự
-
VerificationGate: ATTRIBUTION quote guard never matches a normal quotation (\b around the quote) Đang mở
Độ khó 2/5 1-3 giờ Mức phù hợp với người mới 75/100
danielmiessler/LifeOS#2234 ·
-
T: Bug
Độ khó 2/5 1-3 giờ Mức phù hợp với người mới 75/100
-
Độ khó 2/5 1-3 giờ Mức phù hợp với người mới 65/100
-
Độ khó 1/5 Dưới một giờ Mức phù hợp với người mới 85/100
-
Mend: dependency security vulnerability untriaged
Độ khó 2/5 1-3 giờ Mức phù hợp với người mới 70/100