You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Angular自定义自动完成组件无法通过FormControl获取值问题

问题:Angular自定义自动完成组件无法通过FormControl获取值

我开发了一个带自动完成功能的Angular自定义组件,想用FormControl获取组件的值,但一直拿不到。调用组件的代码如下:

<app-autocomplete-dropdown formControlName="example" [list]="profiloList"></app-autocomplete-dropdown>

尝试访问this.form.controls['example'].value时,无法获取对应的值。表单初始化代码:

public inizialize(): void {
    this.form = this.formBuilder.group({
        example: [null]
    });
}

自定义组件TS文件

export class AutocompleteDropdownComponent implements ControlValueAccessor {

    @Input()
    list: Array<any> = [];

    selectedElement!: Object;

    selectedTitle?: String;

    onChange: any = () => { }
    onTouch: any = () => { }
    touched = false;
    disabled = false;

    constructor() {
    }

    changes(event: Event) {
        if (this.disabled) return
        this.markAsTouched()
        this.selectedElement = event?.target ? (event?.target as HTMLTextAreaElement).value : ''
        this.onChange(this.selectedElement)
    }

    writeValue(obj: any): void {
        this.selectedElement = obj;
    }
    registerOnChange(fn: any): void {
        this.onChange = fn;
    }
    registerOnTouched(fn: any): void {
        this.onTouch = fn;
    }
    setDisabledState?(isDisabled: boolean): void {
        this.disabled = isDisabled;
    }

    markAsTouched() {
        if (!this.touched) {
            this.onTouch();
            this.touched = true;
        }
    }
}

自定义组件HTML文件

<input type="text" class="input" list="list" (keyup)="changes($event)">
<i class="bz-chevron-down icon arrow"></i>

<datalist id="list">
    <option *ngFor="let element of list" [value]="element.objectTitle">
        {{element.objectTitle}}</option>
</datalist>

解决方案

问题出在3个关键细节上,逐一修正即可解决:

  1. 替换事件绑定类型
    当前使用(keyup)事件,但用户选择datalist选项时不会触发keyup,导致值无法同步到FormControl。改用(input)事件,它能覆盖手动输入和选择选项两种场景:
<input type="text" class="input" list="list" (input)="changes($event)">
  1. 修正类型匹配与值同步逻辑
  • selectedElement被声明为Object类型,但实际从input拿到的是字符串(element.objectTitle),类型不匹配,修改为字符串类型:selectedElement!: string;
  • writeValue方法只赋值给selectedElement,没有同步到input的显示值,需要通过模板引用变量+ViewChild实现双向同步:

修改HTML,给input加模板引用:

<input #autocompleteInput type="text" class="input" list="list" (input)="changes($event)">

修改TS代码:

import { ViewChild, ElementRef } from '@angular/core';

export class AutocompleteDropdownComponent implements ControlValueAccessor {
    @ViewChild('autocompleteInput') autocompleteInput!: ElementRef<HTMLInputElement>;
    selectedElement!: string;

    // ...其他代码不变

    writeValue(obj: any): void {
        this.selectedElement = obj || '';
        if (this.autocompleteInput) {
            this.autocompleteInput.nativeElement.value = this.selectedElement;
        }
    }

    changes(event: Event) {
        if (this.disabled) return
        this.markAsTouched()
        // 修正类型为HTMLInputElement(不是textarea)
        this.selectedElement = event?.target ? (event?.target as HTMLInputElement).value : ''
        this.onChange(this.selectedElement)
    }
}
  1. 简化touched状态逻辑
    当前touched变量设为true后不会重置,导致后续操作无法触发onTouch()。直接移除状态判断,每次调用都标记为touched:
markAsTouched() {
    this.onTouch();
}

内容的提问来源于stack exchange,提问作者user18772237

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.12 17:45:45