У меня есть несколько панелей расширения, содержимое которых загружается через <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)
расширения Панель не работает, очевидно, потому что переменная шаблона не существует из-за отложенной загрузки.)