Angular中如何将自定义datalist下拉组件的选中对象传递到父组件?
解决Angular自定义datalist组件双向绑定问题
你遇到的问题是因为自定义组件没有实现双向绑定的机制,导致父组件无法通过[(ngModel)]获取选中对象。下面提供两种可行的解决方法:
方法一:通过@Input + @Output实现双向绑定
这种方式简单直接,适合快速实现组件与父组件的数据同步:
1. 修改自定义组件TS代码
添加输入输出属性,在选中元素时向父组件发射事件:
import { Component, OnInit, Input, Output, EventEmitter } from '@angular/core'; @Component({ selector: 'app-autocomplete-dropdown', templateUrl: './autocomplete-dropdown.component.html', styleUrls: ['./autocomplete-dropdown.component.scss'] }) export class AutocompleteDropdownComponent implements OnInit { @Input() list: any; // 接收父组件传入的选中值 @Input() selectedItem: any; // 发射值变化事件,命名需与输入属性对应(xxxChange) @Output() selectedItemChange = new EventEmitter<any>(); selectedTitle?: String; slideOpen: any = false; ngOnInit(): void { // 初始化时同步父组件传入的选中值到输入框 if (this.selectedItem) { this.selectedTitle = this.selectedItem.objectTitle; } } public saveElement(e): void { let name = e.target.value; let element = this.list.filter(x => x.objectTitle === name)[0]; if (element) { this.selectedItem = element; this.selectedTitle = element.objectTitle; // 向父组件传递选中的对象 this.selectedItemChange.emit(element); } else { e.target.value = ""; this.selectedItem = null; this.selectedItemChange.emit(null); } } }
2. 父组件调用时使用双向绑定语法
<app-autocomplete-dropdown [list]="profiloList" [(selectedItem)]="parentSelectedItem"></app-autocomplete-dropdown>
在父组件TS中定义变量:
parentSelectedItem: any;
此时parentSelectedItem会自动同步自定义组件选中的对象。
方法二:实现ControlValueAccessor让组件支持[(ngModel)]
这种方式符合Angular表单控件的设计规范,能让组件像原生表单控件一样直接使用[(ngModel)]:
1. 修改自定义组件TS代码
实现ControlValueAccessor接口并注册值访问器:
import { Component, OnInit, Input, forwardRef } from '@angular/core'; import { ControlValueAccessor, NG_VALUE_ACCESSOR } from '@angular/forms'; @Component({ selector: 'app-autocomplete-dropdown', templateUrl: './autocomplete-dropdown.component.html', styleUrls: ['./autocomplete-dropdown.component.scss'], // 注册值访问器,让Angular识别该组件为表单控件 providers: [ { provide: NG_VALUE_ACCESSOR, useExisting: forwardRef(() => AutocompleteDropdownComponent), multi: true } ] }) export class AutocompleteDropdownComponent implements OnInit, ControlValueAccessor { @Input() list: any; selectedElement: any; selectedTitle?: String; slideOpen: any = false; // 存储值变化的回调函数 onChange: any = () => {}; // 存储触摸状态的回调函数 onTouched: any = () => {}; ngOnInit(): void {} // 接收父组件通过ngModel传入的值 writeValue(value: any): void { this.selectedElement = value; if (value) { this.selectedTitle = value.objectTitle; } } // 注册值变化回调 registerOnChange(fn: any): void { this.onChange = fn; } // 注册触摸状态回调 registerOnTouched(fn: any): void { this.onTouched = fn; } public saveElement(e): void { let name = e.target.value; let element = this.list.filter(x => x.objectTitle === name)[0]; if (element) { this.selectedElement = element; this.selectedTitle = element.objectTitle; // 通知父组件值发生变化 this.onChange(element); } else { e.target.value = ""; this.selectedElement = null; this.onChange(null); } // 标记控件已被触摸 this.onTouched(); } }
2. 父组件直接使用[(ngModel)]绑定
<app-autocomplete-dropdown [list]="profiloList" [(ngModel)]="parentSelectedItem"></app-autocomplete-dropdown>
父组件TS中定义变量:
parentSelectedItem: any;
此时parentSelectedItem会自动同步组件选中的对象,用法和原生输入控件完全一致。
补充说明
- 方法一适合快速实现简单的双向绑定;方法二更适合需要在表单中使用该组件的场景,扩展性更强。
- 注意datalist仅提供输入建议,用户可输入非列表内的值,你当前代码中的空值处理逻辑能有效避免无效值传入父组件,建议保留。
内容的提问来源于stack exchange,提问作者user18772237
相关产品推荐
相关产品推荐

