Мат расширения панелей синхронизировал содержимое scrollLeft, начальное значение после ленивой загрузки не отражалось в рендере - PullRequest
0 голосов
/ 24 апреля 2020

У меня есть несколько панелей расширения, содержимое которых загружается через <ng-template matExpansionPanelContent> (изначально они закрыты). Содержимое всех них имеет одинаковый размер (в основном это представление в виде календаря со значениями c, указанными для панели). Ширина содержимого превышает ширину экрана, поэтому у меня есть overflow-x: auto и, следовательно, полосы прокрутки.

Я хочу, чтобы полосы прокрутки всех этих панелей были синхронизированы. Для этого я создал сервис, который содержит самую последнюю версию scrollLeft-value (в теме поведения / наблюдаемой) и обновляется с помощью (scroll)="...". В связи с этим я привязал значение из службы к [scrollLeft] на элементах содержимого.

Обычно это работает нормально, но есть одна проблема: когда я открываю панель, прокручиваю и затем открываю другую панель, сначала он находится на scrollLeft == 0 (0 - начальное значение BehaviorSubject). После прокрутки любой из полос все остальные загруженные файлы будут синхронизироваться c.
Очевидно, что введенное значение не берется для первой загрузки / рендеринга. Я решил эту проблему, отправив событие из панели содержимого в ngAfterViewChecked, см. Ниже.

Компонент с панелью расширения:

// html
<mat-expansion-panel ...>
    ...

    <ng-template matExpansionPanelContent>
        <content-component [scrollLeft]="scrollLeft" (scroll)="onScrollLeft($event)" (loaded)="onLoaded($event)" ...></content-component>
    </ng-template>
</mat-expansion-panel>

// ts
public scrollLeft: number;

constructor(private syncScroll: SyncScrollService) {
    this.subscriptions.add(this.syncScroll.scrollLeft.subscribe(value => this.scrollLeft = value));
}

onScrollLeft(event) {
    this.syncScroll.updateScrollLeft(event.srcElement.scrollLeft);
}

onLoaded(contentPanel: ElementRef) {
    contentPanel.nativeElement.scrollLeft = this.scrollLeft;
}

Компонент содержимого:

// ts
@Output() loaded: EventEmitter<ElementRef> = new EventEmitter();
private isLoaded: boolean = false;

constructor(private hostEl: ElementRef) {}

ngAfterViewChecked() {
    if(!this.isLoaded) {
        this.loaded.emit(this.hostEl);
        this.isLoaded = true;
    }
}

// scss
:host {
    overflow-x: auto;
}

Служба SyncScroll:

private scrollLeft$: BehaviorSubject<number> = new BehaviorSubject(0);
public scrollLeft: Observable<number> = this.scrollLeft$.asObservable();

public updateScrollLeft(value: number) {
    this.scrollLeft$.next(value);
}

Мне это кажется немного запутанным. Есть ли лучший / более простой способ сделать это?

(Вещи, такие как использование переменной ref шаблона в компоненте содержимого и установка начального scrollLeft в первые (opened) расширения Панель не работает, очевидно, потому что переменная шаблона не существует из-за отложенной загрузки.)

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...