在 Mat-Select 中滚动到 Mat-0ptions 末尾时触发事件:Angular 6

Men*_*imE 6 javascript typescript angular-material angular angular6

我最近开始修改一个基于 Angular 6 的项目,但遇到了一些问题。因此,我有(假设)4 个 Mat-Select 字段,分别用于语言、货币、国家和组织。

最初所有下拉菜单都有 10 个默认值,我通过调用 API 来获取。我的要求是,一旦用户滚动到选择下拉菜单时打开的 Mat-Options 框的末尾,就进行另一个 API 调用。

我已经提到了这个问题,它工作正常,但有一些问题,我注意到了。该答案涵盖了一个领域的解决方案。如果我们使用多个字段,我们是否必须重复代码?

这是HTML

            <mat-select [disabled]="isDisabled" [(ngModel)]="model.currency" name="currency" (selectionChange)="OnChange('currency',$event.value)" #currency>   
              <mat-option [value]="getCurrency.currencyCode" *ngFor="let getCurrency of fetchCurrency | 
                    filternew:searchCurrencyvaluedrop">{{ getCurrency.currencyDescription }}
              </mat-option>
            </mat-select>

          <mat-select [disabled]="isDisabled" [(ngModel)]="model.language" name="language"
                (selectionChange)="OnChange('language', $event.value)" #language>                      
            <mat-option [value]="getLanguage.languageDescription" *ngFor="let getLanguage of fetchLanguage | 
                  filternew:searchLanguagevaluedrop">{{ getLanguage.languageDescription }}</mat-option>
          </mat-select>
Run Code Online (Sandbox Code Playgroud)

为简单起见,我只添加了两个字段。以下是 .ts 中的代码:


  viewIndex = 0;
  windowSize = 10;
  private readonly PIXEL_TOLERANCE = 3.0;

  ngAfterViewInit() {
    this.selectElemCu.openedChange.subscribe((event) =>
      this.registerPanelScrollEventCurrency(event)
    );
    this.selectElem.openedChange.subscribe((event) =>
      this.registerPanelScrollEventLang(event)
    );
}


//for language field

  registerPanelScrollEventLang(e) {
    if (e) {
      const panel = this.selectElem.panel.nativeElement;
      panel.addEventListener('scroll', event => this.loadNextOnScrollLang(event, this.selectElem.ngControl.name));
    }
  }

  loadNextOnScrollLang(event, select_name) {
    if (this.hasScrolledToBottomLang(event.target)) {
      this.viewIndex += this.windowSize;
      this.modifyPageDetails(select_name)
      this.appService.getAllLanguages(this.standardPageSizeObj, resp => {
        console.log('list of languages', resp)
        this.fetchLanguage.push(...resp['data'])
      }, (error) => {
      });
    }
  }

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

Run Code Online (Sandbox Code Playgroud)

货币下拉代码保持不变。所以,重复是我的第一个问题。第二个是在滚动时进行了两个 API 调用,而不是一个。我可以接受,但是因为有 6 个字段,所以重复太多了。

由于某些安全限制,我什至不能使用外部库。有没有更好的方法来实现这一点。如果需要更多说明,请告诉我。谢谢

Hir*_*ekh 2

我们可以创建一个指令来为我们处理这种滚动逻辑,并且可以防止代码重复。

这是一个演示:https://stackblitz.com/edit/angular-ivy-m2gees ?file=src/app/mat-select-bottom-scroll.directive.ts

这是一个简短的解释:

创建一个自定义指令并获取其中的引用MatSelect

import {Directive,ElementRef,EventEmitter,Input,OnDestroy,Output} from '@angular/core';
import { MatSelect } from '@angular/material/select/';
import { fromEvent, Subject } from 'rxjs';
import { filter, switchMap, takeUntil, throttleTime } from 'rxjs/operators';

@Directive({
  selector: '[appMatSelectScrollBottom]'
})
export class MatSelectScrollBottomDirective implements OnDestroy {
  private readonly BOTTOM_SCROLL_OFFSET = 25;
  @Output('appMatSelectScrollBottom') reachedBottom = new EventEmitter<void>();
  onPanelScrollEvent = event => {};
  unsubscribeAll = new Subject<boolean>();

  constructor(private matSelect: MatSelect) {
    this.matSelect.openedChange
      .pipe(filter(isOpened => !!isOpened),
        switchMap(isOpened =>fromEvent(this.matSelect.panel.nativeElement, 'scroll').pipe(throttleTime(50))), //controles the thrasold of scroll event
        takeUntil(this.unsubscribeAll)
      )
      .subscribe((event: any) => {
        console.log('scroll');
        // console.log(event, event.target.scrollTop, event.target.scrollHeight);
        if (
          event.target.scrollTop >= (event.target.scrollHeight - event.target.offsetHeight - this.BOTTOM_SCROLL_OFFSET)) {
          this.reachedBottom.emit();
        }
      });
  }
  ngOnDestroy(): void {
    this.unsubscribeAll.next(true);
    this.unsubscribeAll.complete();
  }
}
Run Code Online (Sandbox Code Playgroud)

一旦滚动到达底部,该指令就会发出一个事件。

我们从该事件开始openedChange,然后将switchMap其编辑为选择面板的滚动事件。一旦新的打开事件触发,SwitchMap 将自动取消订阅旧的滚动事件。

在您的组件中使用此指令来侦听事件,如下所示。

<mat-form-field>
  <mat-select placeholder="Choose a Doctor" (openedChange)="!$event && reset()"
    (appMatSelectScrollBottom)="loadAllOnScroll()"><!-- liste to the event and call your load data function -->
    <mat-option *ngFor="let dr of viewDoctors;let i = index">{{dr}}</mat-option>
  </mat-select>
</mat-form-field>
Run Code Online (Sandbox Code Playgroud)