Angular ngx-mat-select-search 自定义组件
Posted
技术标签:
【中文标题】Angular ngx-mat-select-search 自定义组件【英文标题】:Angular ngx-mat-select-search Custom Component 【发布时间】:2019-10-25 09:27:21 【问题描述】:我正在尝试使用 ngx-mat-select-search 组件在我的应用程序中放置一个带有搜索栏的 mat-select 样式下拉菜单。 https://www.npmjs.com/package/ngx-mat-select-search
我的下拉菜单工作正常,但我正在尝试将其转换为自定义指令,然后我可以在整个应用程序的多个页面上调用和重用该指令。
到目前为止,我有这个:site-dropdown-component.ts
import AfterViewInit, Component, OnDestroy, OnInit, ViewChild from '@angular/core';
import FormControl from '@angular/forms';
import ReplaySubject, Subject from 'rxjs';
import MatSelect from '@angular/material';
import take, takeUntil from 'rxjs/operators';
@Component(
selector: 'app-site-dropdown',
template: `
<mat-form-field class="w-100">
<mat-select [formControl]="siteCtrl" placeholder="Site" #singleSelect>
<mat-option>
<ngx-mat-select-search [formControl]="siteFilterCtrl" [placeholderLabel]="'Search Sites...'"></ngx-mat-select-search>
</mat-option>
<mat-option *ngFor="let site of filteredSites | async" [value]="site">site.name</mat-option>
</mat-select>
</mat-form-field>
`
)
export class SiteDropdownComponent implements OnInit, OnDestroy, AfterViewInit
/** list of sites */
protected sites: Site[] = SITES;
/** control for the selected site */
public siteCtrl: FormControl = new FormControl();
/** control for the MatSelect filter keyword */
public siteFilterCtrl: FormControl = new FormControl();
/** list of sites filtered by search keyword */
public filteredSites: ReplaySubject<Site[]> = new ReplaySubject<Site[]>(1);
@ViewChild('singleSelect') singleSelect: MatSelect;
/** Subject that emits when the component has been destroyed. */
protected onDestroy = new Subject<void>();
constructor()
ngOnInit(): void
// set initial selection
this.siteCtrl.setValue(this.sites);
// load the initial site list
this.filteredSites.next(this.sites.slice());
// listen for search field value changes
this.siteFilterCtrl.valueChanges
.pipe(takeUntil(this.onDestroy))
.subscribe(() =>
this.filterSites();
);
ngAfterViewInit(): void
this.setInitialValue();
ngOnDestroy(): void
this.onDestroy.next();
this.onDestroy.complete();
/**
* Sets the initial value after the filteredBanks are loaded initially
*/
protected setInitialValue()
this.filteredSites
.pipe(take(1), takeUntil(this.onDestroy))
.subscribe(() =>
// setting the compareWith property to a comparison function
// triggers initializing the selection according to the initial value of
// the form control (i.e. _initializeSelection())
// this needs to be done after the filteredBanks are loaded initially
// and after the mat-option elements are available
this.singleSelect.compareWith = (a: Site, b: Site) => a && b && a.id === b.id;
);
protected filterSites()
if (!this.sites)
return;
// get the search keyword
let search = this.siteFilterCtrl.value;
if (!search)
this.filteredSites.next(this.sites.slice());
return;
else
search = search.toLowerCase();
// filter the sites
this.filteredSites.next(
this.sites.filter(site => site.name.toLowerCase().indexOf(search) > -1)
);
export interface Site
id: string;
name: string;
export const SITES: Site[] = [
id: 'site1', name: 'Site 1',
id: 'site2', name: 'Site 2',
id: 'site3', name: 'Site 3',
];
对于我尝试使用它的组件,我有:
<app-site-dropdown formControlName="site"></app-site-dropdown>
在组件类里面我有一个表单:
this.mySearchForm = this.formBuilder.group(
site: []
);
我可以很好地查看下拉列表并与之交互,但是当我提交表单时,我无法获得所选选项的值。当我尝试mySearchForm.controls['site'].value
时,它总是返回null
我缺少什么能够注入我的自定义下拉组件并在提交表单时检索其值?
更新:
我能够通过执行以下操作使其工作:
在site-dropdown.component.ts
里面,我变了
protected siteCtrl: FormControl;
到
@Input() siteCtrl: FormControl;
在我的 html 中使用自定义下拉菜单,我添加了:
<app-site-dropdown [siteCtrl]="myForm.get('site')"></app-site-dropdown>
这使我可以在提交时将所选值保存到我的表单中。
【问题讨论】:
这正是我一直在寻找的,非常感谢!我实现了服务器端搜索,所以我在 init 之后取出了 setInitialValue() 调用,只是传入了初始值,所以我可以让它显示,但是在你点击它之后会搜索,但它工作得很好。跨度> 【参考方案1】:您可以通过让您的SiteDropdownComponent
实现ControlValueAccessor 接口来获取所选选项的值,如下所示,导致您的SiteDropdownComponent
表现为表单控件并允许使用例如访问该值<app-site-dropdown formControlName="site"></app-site-dropdown>
:
...
import forwardRef from '@angular/core';
import ControlValueAccessor, NG_VALUE_ACCESSOR from '@angular/forms';
@Component(
selector: 'app-site-dropdown',
template: ...
providers: [
provide: NG_VALUE_ACCESSOR,
useExisting: forwardRef(() => SiteDropdownComponent),
multi: true
],
)
export class SiteDropdownComponent implements OnInit, OnDestroy, AfterViewInit, ControlValueAccessor
...
onChange: Function = (_: any) => ;
onTouched: Function = (_: any) => ;
constructor()
ngOnInit()
...
// call this.onChange to notify the parent component that the value has changed
this.siteCtrl.valueChanges
.pipe(takeUntil(this.onDestroy))
.subscribe(value => this.onChange(value))
writeValue(value: string)
// set the value of siteCtrl when the value is set from outside the component
this.siteCtrl.setValue(value);
registerOnChange(fn: Function)
this.onChange = fn;
registerOnTouched(fn: Function)
this.onTouched = fn;
参见例如https://github.com/bithost-gmbh/ngx-mat-select-search/blob/d7ea78d511bbec45143c58c855f013a44d0d5055/src/app/mat-select-search/mat-select-search.component.ts#L134
【讨论】:
我已经从 ng-mat-select-search 实现了问题部分给出的解决方案,它正在工作。但是我怎样才能使它对几个选择框通用?为此,我需要像 SITES 一样每次发送具有不同值的数组:[]。我可以为我的选择框使用带有不同数组的 site-dropdown-component.ts 吗? 地区:地区[],国家:国家[] @RahimjonRustamov 您可以传递任何数组 (items: any[]
) 甚至更好,使用泛型类型 class SiteDropdownComponent<T>
并在 SiteDropdownComponent
中使用类型 T
而不是 Sites
以上是关于Angular ngx-mat-select-search 自定义组件的主要内容,如果未能解决你的问题,请参考以下文章
Angular 6 和业力'无法加载“@angular-devkit/build-angular”,它未注册'
angular.js 的angular.copy angular.extend angular.merge
如何使用 @angular/upgrade 在 Angular 1 应用程序中使用 Angular 2 组件