-
Notifications
You must be signed in to change notification settings - Fork 6.8k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
[Tabs] Automatically page scrolls to top when switching between some tabs #9592
Comments
I have the same Issue. |
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
Well the reason is when you change the tab, the next tab not have that much height of its inner contents so the parent height also decrease. thats why the its scroll to top. try the parent element height fixed like 1000px and then change tab, it will not scroll up. 👍 |
https://stackblitz.com/edit/angular-wjtrxy-g4ksm6 Add a min-height="800px" to parent elemnt of mat-tab-group. :) |
Thanks @umimehar. That's a good workaround. |
This comment has been minimized.
This comment has been minimized.
.fill-available {
min-height: min-height: stretch;
} With this class called in the main container of the page worked for me, only in chrome not in mozilla. |
Better -webkit-fill-available (tested on google chrome). Here is an example https://stackblitz.com/edit/angular-wjtrxy-x9shma |
None of the suggested solutions completely fix the problem for me, I still end up with some weird scrolling behaviors with a pixel edit: I modified @luchoman08 's stackblitz to reflect the problem: I removed some content from tab1 so now if you go to tab4 for example, scroll down a bit, then click tab1, the scrolling bug is still there, switch between those 2 for extra sea sickness effects. |
This comment has been minimized.
This comment has been minimized.
Still a problem with Angular 6.1 and Angular Material 6.4. |
|
Still a problem with angular 7.1.4 and material 7.2 |
This comment has been minimized.
This comment has been minimized.
another hack approach, is to set min-height and padding/margin bottom for short content and to keep a footer in place.
|
"min-height" solution did not work for me. It works, but i had to set min-height to meaningless value. I wrote directive that works for me. You may have to change document.documentElement to your scrolling element. It is not extra clean solution, but it works.
|
This comment has been minimized.
This comment has been minimized.
Still have this problem. Angular 8 |
I might have a solution for this. Its a crude solution, but is seems to be working, at least for me it does :) So let me explain: You need a parent component, which has the entire mat-tab-group code, and child components, for each individual mat-tab body (I suppose you can do without parent/child as well). Parent component HTML: <mat-tab-group (selectedTabChange)="forceScrollPosition($event)">
<mat-tab>
<app-tab-child-0
[scrollPosition]="scrollChild0"
[canUpdateScroll]="updateChild0Scroll"
(scrollChanged)="scrollChanged($event)">
</app-tab-child-0>
</mat-tab>
<mat-tab>
<app-tab-child-1
[scrollPosition]="scrollChild1"
[canUpdateScroll]="updateChild1Scroll"
(scrollChanged)="scrollChanged($event)">
</app-tab-child-1>
</mat-tab>
</mat-tab-group> Parent component TS: import { Component, OnInit, Input, Output, EventEmitter } from '@angular/core';
@Component({
selector: 'app-tab-parent',
templateUrl: './app-tab-parent.html',
styleUrls: ['./app-tab-parent.scss']
})
export class ParentComponent implements OnInit {
// Hold scroll positions for each child (can be also array of values, it doesnt matter)
scrollChild0: number = 0;
scrollChild1: number = 0;
// Permission for child component to emit scroll change
updateChild0Scroll: boolean = true; //The FIRST tab displayed should have this attribute set to ,,true"
updateChild1Scroll: boolean = false;
// There are several ways to trigger method in child, I prefer this one
@ViewChild(TabChild0Component) private tabChild0Component: TabChild0Component;
@ViewChild(TabChild1Component) private tabChild0Component: TabChild1Component;
//Here set new scroll position for specific child tab
public scrollChanged(event: any) {
//example
if(event.index === 0) {
this.scrollChild0 = event.value;
}
else if ...... {
....
}
}
// When selected tab is changed, revalidate permissions and force child to load latest scroll
public forceScrollPosition(event: any) {
//example
this.updateChild0Scroll= event.index === 0;
this.updateChild1Scroll= event.index === 1;
....
// now you need to identify selected tab and force child component to load last saved scroll
if(event.index === 0) {
this.tabChild0Component.loadScroll();
}
else if ...... {
....
}
}
} Child component TS: import { Component, OnInit, Input, Output, EventEmitter } from '@angular/core';
@Component({
selector: 'app-tab-child-0',
templateUrl: './app-tab-child-0.html',
styleUrls: ['./app-tab-child-0.scss']
})
export class TabChild0Component implements OnInit {
@Input() scrollPosition: number;
@Input() canUpdateScroll: boolean;
@Output() scrollChanged = new EventEmitter();
// This path targets mat tab body. the ,,#mat-tab-content-0-0" needs to be changes, depending on
// child index position in the tabs (#mat-tab-content-0-0, #mat-tab-content-0-1, ...)
private readonly elementPath = "#mat-tab-content-0-0 .mat-tab-body-content.ng-trigger.ng-trigger-translateTab";
ngOnInit() {
let element = document.querySelector(this.elementPath);
let base = this;
if(element) {
element.addEventListener('scroll', function() {
// Check if this child is currently focused tab, otherwise it emits 0 by default and defeats the whole
// purpose
if(base.canUpdateScroll) {
base.scrollChanged.emit(document.querySelector(base.elementPath).scrollTop);
}
});
}
}
/** Load last known scroll position */
public loadScroll() {
let element = document.querySelector(this.elementPath);
if(element) {
document.querySelector(this.elementPath).scrollTop = this.scrollPosition;
}
}
} Again, sorry for the crude code, but I hope it can give you at least some basic idea of my solution. If it will be helpful to anyone, well, I am glad I could help :) |
Thank you, I solved scroll to top of page issue using this code 👍 |
Especially bad with variable tab content as |
It would be great to get an update on this. |
I was able to use min-height: 100% on the parent with no other styling. |
Made a small directive that retains the scroll position when you change tabs. import { Directive, ElementRef, OnDestroy } from '@angular/core'
import { fromEvent, Subscription } from 'rxjs'
@Directive({
selector: '[xxxScrollRetainer]'
})
export class ScrollRetainerDirective implements OnDestroy {
private changes: MutationObserver
private lastScrollPosition = 0
private subscription: Subscription
constructor(private elementRef: ElementRef) {
this.changes = new MutationObserver(() => this.rollbackScrollPosition())
this.changes.observe(this.elementRef.nativeElement, { childList: true, subtree: true })
this.subscription = fromEvent(window, 'scroll').subscribe(() => {
this.lastScrollPosition = window.pageYOffset
})
}
private rollbackScrollPosition() {
window.scrollTo(window.pageXOffset, this.lastScrollPosition)
}
ngOnDestroy(): void {
this.subscription.unsubscribe()
this.changes.disconnect()
}
} |
The issue is unrelated to UI tab modules, I can confirmed because the same scrolling happened with ngbTab. The issue, for me at least, is storing tab state in the query params.
Setting For context, the |
This comment has been minimized.
This comment has been minimized.
The problem is the little placeholder element before sliding in the next tab. It has a If it instead latched the height of the outgoing tab, behavior would be as most people expect. |
@jneuhaus20 I dosen't see that, can you send a screenshot ? |
@britvik works for me. Thanks. |
@britvik Which component do you attach your directive to? I attached it to |
@DavidTheProgrammer You can attach it to any element (e.g. div) that contains the tab group. |
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
I'm also having this issue. I've tried @britvik's Directive (doesn't fix for me... fromEvent doesn't appear to fire), I've also tried min-height on containing div. Works in Chrome & Edge but not Firefox. |
I've made this directive based on @ludarous answer, to make it work with Angular CDK scrolling. It work on my side, but not the smoothest option. import { AfterViewInit, Directive, OnInit, OnDestroy } from '@angular/core';
import { MatTabGroup, MatTabChangeEvent } from '@angular/material/tabs';
import { ScrollDispatcher, CdkScrollable } from '@angular/cdk/scrolling';
import { Subscription } from 'rxjs';
@Directive({
selector: '[ScrollRetainer]'
})
export class ScrollRetainerDirective implements AfterViewInit, OnInit, OnDestroy {
constructor(private matTabGroup: MatTabGroup, private scrollDispatcher: ScrollDispatcher) {}
private container: CdkScrollable;
private scrollSub: Subscription;
private tabSub: Subscription;
ngOnInit(): void {
this.scrollSub = this.scrollDispatcher.scrolled().subscribe(
(el: CdkScrollable) => {
this.container = el;
});
}
ngAfterViewInit(): void {
this.tabSub = this.matTabGroup.selectedTabChange.subscribe((tabChangeEvent: MatTabChangeEvent) => {
this.container.scrollTo({
top: this.container.measureScrollOffset('top'),
left: 0,
behavior: 'auto'
});
});
}
ngOnDestroy(): void {
this.scrollSub.unsubscribe();
this.tabSub.unsubscribe();
}
} |
after tweak the if you set if you set So if you have a project with predicted layout, setting min-height might be the quickest hacky way to fix this. |
This issue happening on my angular 9 application, but in different scenario. I have modal pop-up, when i close the modal, page automatically scrolls up in internet explorer. previously with angular 8 and material 7.3.3 I was able to fix this issue by adding window.scroll() event after modal event. but after updating angular 9 and material 9. window.scroll() is not working anymore. I removed window.scroll() event and in chrome and other browsers scroll behaviour working as I expected.. but not in internet explorer, so I am not sure if it is related to window.scroll() compability with IE or is material breaking something. anyone figured out how to solve this issue? |
Still happens in 9.1.12! Please fix this. It was driving me nuts till I used the work around, but work arounds are difficult to remember. my html now has bug comments in it. ugg |
This comment has been minimized.
This comment has been minimized.
We had the same problem and fixed it with this workaround: @Directive({
// tslint:disable-next-line: directive-selector
selector: 'mat-tab-group[scrollFix]'
})
export class PsMatTabGroupScrollFixDirective implements AfterViewInit, OnDestroy {
private matTabGroupEl: HTMLElement = this.el.nativeElement;
private animationSub = Subscription.EMPTY;
constructor(private matTabGroup: MatTabGroup, private el: ElementRef) {
}
public ngAfterViewInit(): void {
const orig = this.matTabGroup._handleClick.bind(this.matTabGroup);
this.matTabGroup._handleClick = (tab, tabHeader, index) => {
if (!tab.disabled) {
this.matTabGroupEl.style.minHeight = this.matTabGroupEl.clientHeight + 'px';
}
return orig(tab, tabHeader, index);
}
this.animationSub = this.matTabGroup.animationDone.subscribe(() => {
this.matTabGroupEl.style.minHeight = 'unset';
});
}
public ngOnDestroy() {
this.animationSub.unsubscribe();
}
} Unfortunatelly it overrides the _handleClick method, which is not in the public api. So it can break at any update, but at least it works for now. |
This comment has been minimized.
This comment has been minimized.
Here's an updated demo that reproduces this issue with 11.0.3. And another demo that demonstrates that this behavior still exists with the MDC-based tabs in |
Same happening to me, for now I'm solving this using tips provided above, but proper fix would be awesome. |
* fix(material/tabs): stop scrolling on tab change Adds min-height to the mat-tab-group wrapper, so page height is preserved as tabs change, and page doesn't scroll up. Fixes #9592 * fix(material/tabs): stop scrolling on tab change Adds min-height to the mat-tab-group wrapper, so page height is preserved as tabs change, and page doesn't scroll up. Fixes #9592 * fix(material/tabs): stop scrolling on tab change … Adds min-height to the mat-tab-group wrapper, so page height is preserved as tabs change, and page doesn't scroll up. Fixes #9592 (cherry picked from commit c12f168)
* fix(material/tabs): stop scrolling on tab change Adds min-height to the mat-tab-group wrapper, so page height is preserved as tabs change, and page doesn't scroll up. Fixes #9592 * fix(material/tabs): stop scrolling on tab change Adds min-height to the mat-tab-group wrapper, so page height is preserved as tabs change, and page doesn't scroll up. Fixes #9592 * fix(material/tabs): stop scrolling on tab change … Adds min-height to the mat-tab-group wrapper, so page height is preserved as tabs change, and page doesn't scroll up. Fixes #9592
* fix(material/tabs): stop scrolling on tab change Adds min-height to the mat-tab-group wrapper, so page height is preserved as tabs change, and page doesn't scroll up. Fixes #9592 * fix(material/tabs): stop scrolling on tab change Adds min-height to the mat-tab-group wrapper, so page height is preserved as tabs change, and page doesn't scroll up. Fixes #9592 * fix(material/tabs): stop scrolling on tab change … Adds min-height to the mat-tab-group wrapper, so page height is preserved as tabs change, and page doesn't scroll up. Fixes #9592 (cherry picked from commit c12f168)
This issue has been automatically locked due to inactivity. Read more about our automatic conversation locking policy. This action has been performed automatically by a bot. |
Bug, feature request, or proposal:
We found a bug. We had top content and a tab group below this content. And then we scrolled a little bit to bottom. We switched between some tabs. Now, page scrolled to top automatically.
It only occurs when we have top content on this page.
What is the expected behavior?
Page should keep scroll position when switching some tabs
What is the current behavior?
Page scrolls to top when switching some tabs
What are the steps to reproduce?
-Step 1: Scroll a little bit to bottom on page
-Step 2: Click on Tab 3
The page will scroll to top.
Demo here: https://stackblitz.com/edit/angular-wjtrxy
What is the use-case or motivation for changing an existing behavior?
A bug
Which versions of Angular, Material, OS, TypeScript, browsers are affected?
Angular 5.0.3 - Material 5.0.2 - Window 10 - Typescript 2.4.2
Is there anything else we should know?
Thanks a lot!
The text was updated successfully, but these errors were encountered: