繁体   English   中英

如何在角度材料垫选择中使用滚动事件?

[英]how to use scroll event in angular material mat select?

我有一个很大的列表,我想在用户向下滚动选择字段时加载它,但是如何在 mat-select 中获取滚动事件没有触发滚动事件的事件。

<mat-form-field>
  <mat-select placeholder="Choose a Doctor" formControlName="selectedDoc" (change)="drSelected()">
    <div *ngFor="let dr of doctors;let i = index" [matTooltip]="getDocDetail(i)" matTooltipPosition="right">
      <mat-option (scroll)="docScroll()" [value]="dr">
        {{dr.name}}
      </mat-option>
    </div>
  </mat-select>
  <mat-hint>List Of Doctor In Your city</mat-hint>
  <mat-error *ngIf="selectedDoc.hasError('required')">Please Select A Dr</mat-error>
</mat-form-field>

(滚动)不起作用,因为 mat-select 没有任何滚动事件,我可以通过任何其他方式实现这一点,我想先显示 10 个项目,然后在用户滚动选项结束时填充其余项目。

查看我创建的Stackblitz

在您的组件,让MatSelect通过ViewChild访问其滚动面板。 然后向面板添加一个事件侦听器,当scrollTop位置超过某个阈值时,它会重新加载医生并更新viewDoctors数组。

allDoctors = ['doctor', 'doctor', ..., 'doctor'];
viewDoctors = this.allDoctors.slice(0, 10);

private readonly RELOAD_TOP_SCROLL_POSITION = 100;
@ViewChild('doctorSelect') selectElem: MatSelect;

ngOnInit() {
  this.selectElem.onOpen.subscribe(() => this.registerPanelScrollEvent());
}

registerPanelScrollEvent() {
  const panel = this.selectElem.panel.nativeElement;
  panel.addEventListener('scroll', event => this.loadAllOnScroll(event));
}

loadAllOnScroll(event) {
  if (event.target.scrollTop > this.RELOAD_TOP_SCROLL_POSITION) {
    this.viewDoctors = this.allDoctors;
  }
}

不要忘记将mat-select分配给模板中的变量,以便您可以通过ViewChild访问它:

<mat-form-field>
  <mat-select placeholder="Choose a Doctor" #doctorSelect>
                                            ^^^^^^^^^^^^^ 
    <mat-option *ngFor="let dr of viewDoctors;let i = index">
      {{dr}}
    </mat-option>
  </mat-select>
</mat-form-field>

这只是一个非常基本的设置来说明这个想法。 您可能想要显示加载动画,清理事件侦听器,...

到目前为止, mat-select组件的无限滚动仍然不可用,并保持为一个未解决的问题。 同时,看看ng-mat-select-infinite-scroll ,你可以用它来延迟加载你的数据。

import { MatFormFieldModule, MatSelectModule } from '@angular/material';
import {MatSelectInfiniteScrollModule} from 'ng-mat-select-infinite-scroll';

@NgModule({
  declarations: [
    AppComponent
  ],
  imports: [
    BrowserModule,
    BrowserAnimationsModule,
    MatFormFieldModule,
    MatSelectModule,
    MatSelectInfiniteScrollModule
  ],
  providers: [],
  bootstrap: [AppComponent]
})
export class AppModule {
}

组件

  total = 100;
  data = Array.from({length: this.total}).map((_, i) => `Option ${i}`);
  limit = 10;
  offset = 0;
  options = new BehaviorSubject<string[]>([]);
  options$: Observable<string[]>;

  constructor() {
    this.options$ = this.options.asObservable().pipe(
      scan((acc, curr) => {
        return [...acc, ...curr];
      }, [])
    );
  }

  ngOnInit() {
    this.getNextBatch();
  }

  getNextBatch() {
    const result = this.data.slice(this.offset, this.offset + this.limit);
    this.options.next(result);
    this.offset += this.limit;
  }

模板

  <mat-form-field appearance="outline">
    <mat-label>Select</mat-label>
    <mat-select msInfiniteScroll (infiniteScroll)="getNextBatch()" [complete]="offset === data.length">
      <mat-option *ngFor="let option of options$ | async" [value]="option">{{option}}</mat-option>
    </mat-select>
  </mat-form-field>

这是一个工作示例

基于 Kim 的回答,滚动高度和顶部可用于检测用户何时到达下拉列表的底部(请参阅此 SO 问题

我还更新了逻辑以在滚动时加载接下来的 10 条记录,以防整个数据集太大而无法一次性加载。

import { Component, OnInit, ViewChild } from '@angular/core';
import { MatSelect } from '@angular/material/select';

@Component({
  selector: 'toolbar-multirow-example',
  templateUrl: 'toolbar-multirow-example.html',
  styleUrls: ['toolbar-multirow-example.css']
})
export class ToolbarMultirowExample implements OnInit {
  allDoctors = Array.from(new Array(3000).keys()).map(i => 'Doctor ' + i);
  viewDoctors = this.allDoctors.slice(0, 10);
  viewIndex = 0;
  windowSize = 10;  
  private readonly PIXEL_TOLERANCE = 3.0;
  @ViewChild('doctorSelect') selectElem: MatSelect;

  ngOnInit() {
    this.selectElem.openedChange.subscribe(() =>
      this.registerPanelScrollEvent()
    );
  }

  registerPanelScrollEvent() {
    const panel = this.selectElem.panel.nativeElement;
    panel.addEventListener('scroll', event => this.loadNextOnScroll(event));
  }

  loadNextOnScroll(event) {    
    if (this.hasScrolledToBottom(event.target)) {
      console.log('Scrolled to bottom');
      this.viewIndex += this.windowSize;      
      this.viewDoctors = this.allDoctors.slice(0,this.viewIndex);      
    }
  }

  private hasScrolledToBottom(target): boolean {    
    return Math.abs(target.scrollHeight - target.scrollTop - target.clientHeight) < this.PIXEL_TOLERANCE;
  }

  reset() {
    this.viewDoctors = this.allDoctors.slice(0, 10);
  }
}

这里找到工作示例

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM