typescript 如何在Angular 8中打开自动完成时将选项滚动到视图中-可编辑下拉列表

ibrsph3r  于 2023-06-24  发布在  TypeScript
关注(0)|答案(3)|浏览(158)

我试图创建一个字段,其行为类似于选择,但输入是可编辑的。要求是“用户应该能够从选项中选择或键入有效值”。这些选项不被过滤,而是应该关注选项中的匹配值。我试图创建一个使用垫自动完成,但我无法修复滚动部分。选择后再次键入或聚焦字段时,如何将所选选项滚动到视图中?
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;
}

https://stackblitz.com/edit/angular-ivy-vetnpq

umuewwlo

umuewwlo1#

好了,我们走吧...
让我们从一个小StackBlitz demo开始。
请注意,当有人从输入中使用keydown时,您还应该关注选定的元素,我没有实现,因为它有点超出了问题的范围。总的来说,我建议使用默认行为,但既然你问..

CSS

在html中有一个div,你可以通过它的role='listbox'来识别。这个div包含mat-option元素。当mat-option元素不适合div时,div将添加一个带有overflow: auto的滚动条。所以我们只需要在div上设置scrollTop值即可滚动。

如何获取元素

通过autocomplete对象的一个名为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;
  }
}

最后一句话

这是所有的乐趣和傻笑玩,但认真地只是使用默认的行为和保存你未来的自己一些痛苦。

ao218c7q

ao218c7q2#

如果我理解你想要的是添加用户输入的选项到mat-automcomplete的选项。如果我明白了你的观点,那就试着看看下面的StackBlitz编辑的代码edited-stackblitz
我已经添加了一个按钮,当用户按下按钮时,我将选项添加到自动完成列表中。你也可以拦截当用户按下“回车”,并触发动作,我已经添加到按钮。
下面是编辑后的代码:

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);
  }

让我知道我是否理解正确。

vpfxa7rd

vpfxa7rd3#

要将面板滚动焦点与选定项目和激活项目同步,您可以轻松利用mat-autocomplete元素上的optionActivatedopened事件:

<mat-autocomplete 
(opened)="onPanelOpened()"
(optionActivated)="onOptionActivated($event)">

</mat-autocomplete>

ts实现onOptionActivated方法只用于keydown和keyup聚焦在激活的元素上,还实现onPanelOpened方法在打开面板后聚焦在第一个选中的项目上:

@ViewChild(MatAutocomplete) autoComplete!: MatAutocomplete;

 onPanelOpened() {
   const firstSelectedOption = this.autoComplete.options.find(o => o.selected);

   firstSelectedOption?._getHostElement()?.scrollIntoView({
     block: 'center',
   });
 }

onOptionActivated(event: MatAutocompleteActivatedEvent) {
   event.option?._getHostElement()?.scrollIntoView({
     block: 'end',
   });
 }

相关问题