Угловой материал Sidenav cdkScrollable

Angular Material CDK предоставляет Directive CdkScrollable, который позволяет вам прослушивать ScrollEvent определенного контейнера.
Теперь я пытаюсь получить доступ к CdkScrollable из MatSidenavContent, который добавлен по умолчанию.
Однако мой @ViewChild(CdkScrollable) и @ContentChild(CdkScrollable) всегда не определены.

Мой Component выглядит примерно так:

<mat-sidenav-container>
    <mat-sidenav>Sidenav content</mat-sidenav>
    <div>Main content</div>
</mat-sidenav-container>

В результате DOM выглядит примерно так:

<mat-sidenav-container>
    <div class="mat-drawer-backdrop"></div>
    <div tabindex="-1" class="cdk-visually-hidden cdk-focus-trap-anchor"></div>
    <mat-sidenav>Sidenav content</mat-sidenav>
    <mat-sidenav-content cdkScrollable>
          <div>Main content</div>
    </mat-sidenav-content>
</mat-sidenav-container>

mat-sidenav-content Component, который создается автоматически, использует CdkScrollable-директиву, к которой мне нужно получить доступ.
Теперь у меня вопрос:
Можно ли получить доступ к этому Directive, и если да, то как?


person Springrbua    schedule 28.11.2017    source источник
comment
Забавно, что документация по материалам показывает это в качестве примера, но, что бы я ни пробовал, ВСЮ НОЧЬ, это не работает.   -  person j_walker_dev    schedule 14.03.2018
comment
@j_walker_dev Некоторое время назад я открыл проблему на @ angular / material, и теперь доступен экземпляр CdkScrollable. См. здесь   -  person Springrbua    schedule 14.03.2018
comment
Спасибо за помощь Springbua. Мне никогда не удавалось заставить this.sidenavContainer.scrollable быть чем-то другим, кроме undefined. Вместо этого мне пришлось использовать только CdkScrollable. @ViewChild (MatSidenavContent) до сих пор не работает у меня, пытаясь получить свиток. Это очень странно. Еще раз спасибо! Я рад, что у вас все заработало!   -  person j_walker_dev    schedule 20.03.2018


Ответы (2)


  1. Добавьте в ваше приложение модуль импорта: ScrollDispatchModule.
  2. Добавьте cdkScrollable в свой mat-sidenav-content:

<mat-sidenav-content cdkScrollable> </mat-sidenav-content>

  1. В корневом компоненте:

а) вставить ScrollDispatcher из @angular/cdk/overlay и подписаться на прокрутку:

constructor(public scroll: ScrollDispatcher) {

    this.scrollingSubscription = this.scroll
          .scrolled()
          .subscribe((data: CdkScrollable) => {
            this.onWindowScroll(data);
          });
}

в) делать что-нибудь при прокрутке, например проверить смещение

private onWindowScroll(data: CdkScrollable) {
    const scrollTop = data.getElementRef().nativeElement.scrollTop || 0;
    if (this.lastOffset > scrollTop) {
      // console.log('Show toolbar');
    } else if (scrollTop < 10) {
      // console.log('Show toolbar');
    } else if (scrollTop > 100) {
      // console.log('Hide toolbar');
    }

    this.lastOffset = scrollTop;
  }

Документация: https://material.angular.io/cdk/scrolling/api

Обновление Angular 9:

Используйте import {ScrollingModule} from '@angular/cdk/scrolling', ScrollDispatchModule устарело

person Sebastian Denis    schedule 12.06.2018
comment
Думаю, можно и так? const scrollable = this.scrollDispatcher.getAncestorScrollContainers (this.elementRef) [0]; console.log (scrollable.getElementRef (). nativeElement.scrollTop); - person Kim T; 12.06.2018
comment
Не могли бы вы объяснить, как использовать метод elementScrolled в директиве CdkScrollable вместо scroll.scrolled? - person Ganesh Matkam; 18.06.2018
comment
data всегда undefined. Почему? - person smartmouse; 18.02.2019
comment
К сведению - ScrollDispatchModule был переименован в ScrollingModule - person Christian Jensen; 19.04.2019
comment
@smartmouse, это может помочь programmersought.com/article/3361447407/ - person Amirreza; 15.03.2020
comment
Да, данные для меня тоже не определены. @smartmouse ты нашел какое-нибудь решение? - person Saurabh Tiwari; 10.01.2021

Некоторое время назад я открыл проблему на @ angular / material, и теперь они открывают CdkScrollable-Instance.
Чтобы использовать его, вам нужно получить доступ к MatSidenavContainer с помощью @ViewChild(MatSidenavContainer. У этого экземпляра есть общедоступный член scrollable, то есть экземпляр CdkScrollable.
Пример можно найти здесь

Изменить: поскольку пример не очень полный и некоторые люди испытывают трудности с его реализацией, я напишу здесь свой собственный пример:

HTML:

<mat-sidenav-container>
    <mat-sidenav #sidenav>
        Sidenav Content
    </mat-sidenav>
    <div>
        Main Content
    </div>
</mat-sidenav-container>

TypeScript:

import { Component, AfterViewInit, ViewChild } from '@angular/core';
import { MatSidenavContainer } from '@angular/material';

@Component({
  selector: 'my-app',
  templateUrl: './app.component.html',
  styleUrls: [ './app.component.css' ]
})
export class AppComponent implements AfterViewInit  {
  @ViewChild(MatSidenavContainer) sidenavContainer: MatSidenavContainer;

    constructor() {
    }

    ngAfterViewInit() {
      console.log(this.sidenavContainer.scrollable);
    }
}

Важно:

  1. Не используйте <mat-sidenav-content>. Этот тег создается автоматически, и к нему прикреплена директива cdkScrollable. Если вы используете <mat-sidenav-content> в своем собственном шаблоне, scrollable будет неопределенным.
  2. Используйте AfterViewInit вместо OnInit. Насколько мне известно, @ViewChild решено в AfterViewInit, OnInit, вероятно, слишком рано.
person Springrbua    schedule 27.04.2018
comment
Я не могу заставить его работать. Вот мой пример. Я также обнаружил эту проблему на @ angular / material. - person stevo; 23.05.2018
comment
@stevo Я отредактировал свой ответ. Проблема в вашем примере в том, что вы сами пишете <mat-sidenav-content>. Этот тег автоматически добавляется материалом angular и включает cdkScrollable. В вашем примере это отсутствует в окончательном HTML (я видел это в инструментах разработчика). Также вы используете ngOnInit, но вам следует использовать AfterViewInit, если вы работаете с ViewChild. - person Springrbua; 24.05.2018
comment
Большое спасибо @Springrbua! Я создал новый пример на Stackblitz. Теперь я могу подписаться на this.sidenavContainer.scrollable.elementScrolled(), но ничего не происходит. - person stevo; 24.05.2018
comment
Взгляните на material.angular.io/cdk/scrolling/api#CdkScrollable API CdkScrollable должен помочь. Если нет, не стесняйтесь создавать новый вопрос и дайте мне знать об этом. - person Springrbua; 24.05.2018
comment
№1 под важным только что спас мое психическое состояние. Спасибо - person john; 18.07.2018