如何在 Angular 中打开自动完成时将选项滚动到视图中 8 - 可编辑下拉列表
How to scroll option into view on opening autocomplete in Angular 8 - Editable dropdown
我正在尝试创建一个行为类似于 select 但输入是可编辑的字段。要求是'The user should be able to select from options or type in a valid value'。选项不会被过滤,而是应该关注选项中的匹配值。我正在尝试使用 mat autocomplete 创建一个,但我无法修复滚动部分。在 selection 之后再次输入或聚焦字段时,如何将 selected 选项滚动到视图中?
HTML
<div>
<mat-form-field [appearance]="'outline'">
<mat-label>Select color</mat-label>
<input type="text" matInput [(ngModel)]="color" [matAutocomplete]="colorOptions">
<i class="icon-caret-down select-arrow" matSuffix></i>
<mat-hint>Select or type a color</mat-hint>
</mat-form-field>
<mat-autocomplete #colorOptions="matAutocomplete">
<mat-option *ngFor="let option of colors; let i=index" [value]="option"
[ngClass]="{'active-option': option == color}">
{{option}}
</mat-option>
</mat-autocomplete>
</div>
TS
public colors = ['Red', 'Green', 'Blue', 'Yellow', 'Orange', 'White', 'Black', 'Purple', 'Grey', 'Brown'];
public color = '';
SCSS
.active-option {
background-color: #f5f5f5 !important;
font-weight: bold !important;
}
如果我理解你想要的是将用户键入的选项添加到 mat-autocomplete 的选项中。如果我明白您的意思,请尝试查看以下代码的 StackBlitz 编辑 edited-stackblitz。
我添加了一个按钮,当用户按下该按钮时,我将选项添加到自动完成列表中。您还可以在用户按下“enter”并触发我添加到按钮的操作时进行拦截。
这里是编辑后的代码:
HTML:
<div [formGroup]="testForm">
<mat-form-field [appearance]="'outline'">
<mat-label>Select color</mat-label>
<input type="text" matInput formControlName="color"
[matAutocomplete]="colorOptions" [(ngModel)]="currentOption">
<i class="icon-caret-down select-arrow" matSuffix></i>
<mat-hint>Select or type a color</mat-hint>
</mat-form-field>
<mat-autocomplete #colorOptions="matAutocomplete">
<mat-option *ngFor="let option of colors; let i=index" [value]="option"
[ngClass]="{'active-option': option == testForm.controls.color.value}">
{{option}}
</mat-option>
</mat-autocomplete>
<button (click)="addOption()">+</button>
{{currentOption}}
</div>
TS:
name = 'Angular ' + VERSION.major;
color = '';
colors = ['Red', 'Green', 'Blue', 'Yellow', 'Orange', 'White', 'Black', 'Purple', 'Grey', 'Brown'];
testForm: FormGroup;
ngOnInit(){
this.testForm = new FormGroup({
color: new FormControl('')
})
}
public currentOption: any;
public addOption(): void {
this.colors.push(this.currentOption);
}
让我知道我是否理解正确。
好的,我们开始....
让我们从一点开始 StackBlitz demo。
请注意,当有人使用输入中的 keydown 时,您还应该关注所选元素,我没有实现,因为它有点超出问题的范围。总的来说,我建议使用默认行为,但既然你问了..
css
在html中有一个div
你可以通过它的role='listbox'
来识别。此 div
包含 mat-option
个元素。当 mat-option
元素不适合 div
时,div 将添加带有 overflow: auto
的滚动条。所以我们只需要在 div 上设置 scrollTop
值即可滚动。
如何获取元素
通过名为 panel
的自动完成对象的 属性 获取 div
。为此,获取自动完成对象并使用 @ViewChild()
.
引用它
计算要在scrollTop上设置的值
要计算值,请获取 mat-option
的高度。默认值为 48,因此您可以直接设置它。您应该能够从 AUTOCOMPLETE_OPTION_HEIGHT
.
中获取高度
注意:我无法通过修改此值获得可见的结果。也许我做错了什么。或者可能有什么原因导致修改这个常量没有实际效果。所以我直接设置为默认值48.
要获得正确的 scrollTop
值,请使用匹配元素的索引计算它。
通过方法调用添加逻辑
使用检测输入值变化的方法调用此逻辑:(input)='changed_input()
。
下面是我的代码
app.module.ts
import { NgModule } from '@angular/core';
import { BrowserModule } from '@angular/platform-browser';
import { FormsModule, ReactiveFormsModule } from '@angular/forms';
import { AppComponent } from './app.component';
import { HelloComponent } from './hello.component';
import { MatAutocompleteModule } from '@angular/material/autocomplete';
import { MatFormFieldModule } from '@angular/material/form-field';
import { MatInputModule } from '@angular/material/input';
import { BrowserAnimationsModule } from '@angular/platform-browser/animations';
import {AUTOCOMPLETE_OPTION_HEIGHT} from '@angular/material/autocomplete';
@NgModule({
imports: [
BrowserModule,
BrowserAnimationsModule,
FormsModule,
ReactiveFormsModule,
MatFormFieldModule,
MatInputModule,
MatAutocompleteModule
],
declarations: [ AppComponent, HelloComponent ],
bootstrap: [ AppComponent ],
providers: [
{provide: AUTOCOMPLETE_OPTION_HEIGHT, useValue: 48 }
]
})
export class AppModule { }
app.component.html
<div [formGroup]="testForm">
<mat-form-field [appearance]="'outline'">
<mat-label>Select color</mat-label>
<input type="text" matInput [(ngModel)]="color"
(input)='changed_input()'formControlName="color" [matAutocomplete]="colorOptions">
<i class="icon-caret-down select-arrow" matSuffix></i>
<mat-hint>Select or type a color</mat-hint>
</mat-form-field>
<mat-autocomplete
#matAutocomplete #colorOptions="matAutocomplete">
<mat-option *ngFor="let option of colors; let i=index" [value]="option">
{{option}}
</mat-option>
</mat-autocomplete>
</div>
app.component.ts
import { Component, VERSION, ViewChild, Inject } from '@angular/core';
import { FormGroup, FormControl } from '@angular/forms';
import {AUTOCOMPLETE_OPTION_HEIGHT} from '@angular/material/autocomplete';
@Component({
selector: 'my-app',
templateUrl: './app.component.html',
styleUrls: [ './app.component.css' ]
})
export class AppComponent {
@ViewChild('matAutocomplete') matAutocomplete;
color = '';
colors = ['Red', 'Green', 'Blue', 'Yellow', 'Orange', 'White', 'Black', 'Purple', 'Grey', 'Brown'];
testForm: FormGroup;
constructor(
@Inject(AUTOCOMPLETE_OPTION_HEIGHT) public option_height: number
) {}
ngOnInit(){
this.testForm = new FormGroup({
color: new FormControl('')
})
}
public changed_input(): void {
const color_index = this.colors.findIndex( color_option => {
return color_option.toLowerCase() === this.color.toLowerCase();
});
if(color_index === -1 ) return;
this.matAutocomplete.panel.nativeElement.scrollTop = this.option_height*color_index;
}
}
最后的说明
这一切都很有趣和咯咯笑,但认真地使用默认行为并为你未来的自己省去一些痛苦。
我正在尝试创建一个行为类似于 select 但输入是可编辑的字段。要求是'The user should be able to select from options or type in a valid value'。选项不会被过滤,而是应该关注选项中的匹配值。我正在尝试使用 mat autocomplete 创建一个,但我无法修复滚动部分。在 selection 之后再次输入或聚焦字段时,如何将 selected 选项滚动到视图中?
HTML
<div>
<mat-form-field [appearance]="'outline'">
<mat-label>Select color</mat-label>
<input type="text" matInput [(ngModel)]="color" [matAutocomplete]="colorOptions">
<i class="icon-caret-down select-arrow" matSuffix></i>
<mat-hint>Select or type a color</mat-hint>
</mat-form-field>
<mat-autocomplete #colorOptions="matAutocomplete">
<mat-option *ngFor="let option of colors; let i=index" [value]="option"
[ngClass]="{'active-option': option == color}">
{{option}}
</mat-option>
</mat-autocomplete>
</div>
TS
public colors = ['Red', 'Green', 'Blue', 'Yellow', 'Orange', 'White', 'Black', 'Purple', 'Grey', 'Brown'];
public color = '';
SCSS
.active-option {
background-color: #f5f5f5 !important;
font-weight: bold !important;
}
如果我理解你想要的是将用户键入的选项添加到 mat-autocomplete 的选项中。如果我明白您的意思,请尝试查看以下代码的 StackBlitz 编辑 edited-stackblitz。
我添加了一个按钮,当用户按下该按钮时,我将选项添加到自动完成列表中。您还可以在用户按下“enter”并触发我添加到按钮的操作时进行拦截。
这里是编辑后的代码:
HTML:
<div [formGroup]="testForm">
<mat-form-field [appearance]="'outline'">
<mat-label>Select color</mat-label>
<input type="text" matInput formControlName="color"
[matAutocomplete]="colorOptions" [(ngModel)]="currentOption">
<i class="icon-caret-down select-arrow" matSuffix></i>
<mat-hint>Select or type a color</mat-hint>
</mat-form-field>
<mat-autocomplete #colorOptions="matAutocomplete">
<mat-option *ngFor="let option of colors; let i=index" [value]="option"
[ngClass]="{'active-option': option == testForm.controls.color.value}">
{{option}}
</mat-option>
</mat-autocomplete>
<button (click)="addOption()">+</button>
{{currentOption}}
</div>
TS:
name = 'Angular ' + VERSION.major;
color = '';
colors = ['Red', 'Green', 'Blue', 'Yellow', 'Orange', 'White', 'Black', 'Purple', 'Grey', 'Brown'];
testForm: FormGroup;
ngOnInit(){
this.testForm = new FormGroup({
color: new FormControl('')
})
}
public currentOption: any;
public addOption(): void {
this.colors.push(this.currentOption);
}
让我知道我是否理解正确。
好的,我们开始....
让我们从一点开始 StackBlitz demo。
请注意,当有人使用输入中的 keydown 时,您还应该关注所选元素,我没有实现,因为它有点超出问题的范围。总的来说,我建议使用默认行为,但既然你问了..
css
在html中有一个div
你可以通过它的role='listbox'
来识别。此 div
包含 mat-option
个元素。当 mat-option
元素不适合 div
时,div 将添加带有 overflow: auto
的滚动条。所以我们只需要在 div 上设置 scrollTop
值即可滚动。
如何获取元素
通过名为 panel
的自动完成对象的 属性 获取 div
。为此,获取自动完成对象并使用 @ViewChild()
.
计算要在scrollTop上设置的值
要计算值,请获取 mat-option
的高度。默认值为 48,因此您可以直接设置它。您应该能够从 AUTOCOMPLETE_OPTION_HEIGHT
.
注意:我无法通过修改此值获得可见的结果。也许我做错了什么。或者可能有什么原因导致修改这个常量没有实际效果。所以我直接设置为默认值48.
要获得正确的 scrollTop
值,请使用匹配元素的索引计算它。
通过方法调用添加逻辑
使用检测输入值变化的方法调用此逻辑:(input)='changed_input()
。
下面是我的代码
app.module.ts
import { NgModule } from '@angular/core';
import { BrowserModule } from '@angular/platform-browser';
import { FormsModule, ReactiveFormsModule } from '@angular/forms';
import { AppComponent } from './app.component';
import { HelloComponent } from './hello.component';
import { MatAutocompleteModule } from '@angular/material/autocomplete';
import { MatFormFieldModule } from '@angular/material/form-field';
import { MatInputModule } from '@angular/material/input';
import { BrowserAnimationsModule } from '@angular/platform-browser/animations';
import {AUTOCOMPLETE_OPTION_HEIGHT} from '@angular/material/autocomplete';
@NgModule({
imports: [
BrowserModule,
BrowserAnimationsModule,
FormsModule,
ReactiveFormsModule,
MatFormFieldModule,
MatInputModule,
MatAutocompleteModule
],
declarations: [ AppComponent, HelloComponent ],
bootstrap: [ AppComponent ],
providers: [
{provide: AUTOCOMPLETE_OPTION_HEIGHT, useValue: 48 }
]
})
export class AppModule { }
app.component.html
<div [formGroup]="testForm">
<mat-form-field [appearance]="'outline'">
<mat-label>Select color</mat-label>
<input type="text" matInput [(ngModel)]="color"
(input)='changed_input()'formControlName="color" [matAutocomplete]="colorOptions">
<i class="icon-caret-down select-arrow" matSuffix></i>
<mat-hint>Select or type a color</mat-hint>
</mat-form-field>
<mat-autocomplete
#matAutocomplete #colorOptions="matAutocomplete">
<mat-option *ngFor="let option of colors; let i=index" [value]="option">
{{option}}
</mat-option>
</mat-autocomplete>
</div>
app.component.ts
import { Component, VERSION, ViewChild, Inject } from '@angular/core';
import { FormGroup, FormControl } from '@angular/forms';
import {AUTOCOMPLETE_OPTION_HEIGHT} from '@angular/material/autocomplete';
@Component({
selector: 'my-app',
templateUrl: './app.component.html',
styleUrls: [ './app.component.css' ]
})
export class AppComponent {
@ViewChild('matAutocomplete') matAutocomplete;
color = '';
colors = ['Red', 'Green', 'Blue', 'Yellow', 'Orange', 'White', 'Black', 'Purple', 'Grey', 'Brown'];
testForm: FormGroup;
constructor(
@Inject(AUTOCOMPLETE_OPTION_HEIGHT) public option_height: number
) {}
ngOnInit(){
this.testForm = new FormGroup({
color: new FormControl('')
})
}
public changed_input(): void {
const color_index = this.colors.findIndex( color_option => {
return color_option.toLowerCase() === this.color.toLowerCase();
});
if(color_index === -1 ) return;
this.matAutocomplete.panel.nativeElement.scrollTop = this.option_height*color_index;
}
}
最后的说明
这一切都很有趣和咯咯笑,但认真地使用默认行为并为你未来的自己省去一些痛苦。