Miałem ten sam problem, używam AfterViewChecked
i@ViewChild
kombinacji (Angular2 beta.3).
Składnik:
import {..., AfterViewChecked, ElementRef, ViewChild, OnInit} from 'angular2/core'
@Component({
...
})
export class ChannelComponent implements OnInit, AfterViewChecked {
@ViewChild('scrollMe') private myScrollContainer: ElementRef;
ngOnInit() {
this.scrollToBottom();
}
ngAfterViewChecked() {
this.scrollToBottom();
}
scrollToBottom(): void {
try {
this.myScrollContainer.nativeElement.scrollTop = this.myScrollContainer.nativeElement.scrollHeight;
} catch(err) { }
}
}
Szablon:
<div #scrollMe style="overflow: scroll; height: xyz;">
<div class="..."
*ngFor="..."
...>
</div>
</div>
Oczywiście jest to dość podstawowe. AfterViewChecked
Wyzwala za każdym razem widok sprawdzono:
Zaimplementuj ten interfejs, aby otrzymywać powiadomienia po każdym sprawdzeniu widoku komponentu.
Jeśli masz pole wejściowe do wysyłania wiadomości, na przykład to zdarzenie jest wywoływane po każdym naciśnięciu klawisza (tylko dla przykładu). Ale jeśli zapiszesz, czy użytkownik przewinął ręcznie, a następnie pominiesz scrollToBottom()
, powinno być dobrze.
Najprostszym i najlepszym rozwiązaniem jest:
Dodaj tę
#scrollMe [scrollTop]="scrollMe.scrollHeight"
prostą rzecz po stronie szablonuOto link do PRACY DEMO (z fałszywą aplikacją do czatu) I PEŁNY KOD
źródło
Expression has changed after it was checked. Previous value: 'scrollTop: 1758'. Current value: 'scrollTop: 1734'
. Czy rozwiązałeś to?Dodałem sprawdzenie, czy użytkownik próbował przewijać w górę.
Zostawię to tutaj, jeśli ktoś tego chce :)
i kod:
źródło
Zaakceptowana odpowiedź odpala się podczas przewijania wiadomości, aby tego uniknąć.
Chcesz takiego szablonu.
Następnie chcesz użyć adnotacji ViewChildren, aby zasubskrybować nowe elementy wiadomości dodawane do strony.
źródło
Rozważ użycie
Zobacz https://developer.mozilla.org/en-US/docs/Web/API/Element/scrollIntoView
źródło
Jeśli chcesz mieć pewność, że przewijasz do końca po zakończeniu * ngFor, możesz użyć tego.
Ważne tutaj, zmienna „last” określa, czy aktualnie znajdujesz się przy ostatniej pozycji, więc możesz wywołać metodę „scrollToBottom”
źródło
źródło
Dzielenie się moim rozwiązaniem, ponieważ nie byłem w pełni zadowolony z reszty. Mój problem
AfterViewChecked
polega na tym, że czasami przewijam w górę iz jakiegoś powodu ten haczyk życia jest wywoływany i przewija mnie w dół, nawet jeśli nie ma nowych wiadomości. Próbowałem użyć,OnChanges
ale to był problem, który doprowadził mnie do tego rozwiązania. Niestety, używając tylkoDoCheck
, przewijało się w dół przed renderowaniem wiadomości, co też nie było przydatne, więc połączyłem je tak, aby DoCheck w zasadzie wskazywał,AfterViewChecked
czy powinien wywołaćscrollToBottom
.Chętnie otrzymam informację zwrotną
chat.component.html
chat.component.sass
źródło
const isScrolledDown = Math.abs(this.scrollable.nativeElement.scrollHeight - this.scrollable.nativeElement.scrollTop - this.scrollable.nativeElement.clientHeight) <= 3.0;
(gdzie 3,0 to tolerancja w pikselach). Może być stosowany wngDoCheck
celu warunkowo nie jest ustawionashouldScrollDown
natrue
jeśli użytkownik ręcznie przewijane w górę.ngAfterViewChecked
z drugą wartością logiczną. ZmieniłemshouldScrollDown
nazwę na,numberOfMessagesChanged
abyif (this.numberOfMessagesChanged && !isScrolledDown)
, ale myślę, że nie zrozumiałeś intencji mojej sugestii. Moim prawdziwym zamiarem jest, aby nie przewijać automatycznie w dół, nawet po dodaniu nowej wiadomości, jeśli użytkownik ręcznie przewija w górę. Bez tego, jeśli przewiniesz w górę, aby zobaczyć historię, czat przewinie się w dół, gdy tylko nadejdzie nowa wiadomość. Może to być bardzo irytujące zachowanie. :) Tak więc moją sugestią było sprawdzenie, czy czat jest przewijany w górę przed dodaniem nowej wiadomości do DOM i nie przewijanie automatyczne, jeśli tak jest.ngAfterViewChecked
jest za późno, ponieważ DOM już się zmienił.Odpowiedź Viveka zadziałała dla mnie, ale spowodowała, że wyrażenie zmieniło się po sprawdzeniu błędu. Żaden z komentarzy nie działał dla mnie, ale zmieniłem strategię wykrywania zmian.
źródło
W kątowym używaniu sidenav Material Design musiałem użyć następującego:
źródło
źródło
Po przeczytaniu innych rozwiązań najlepszym rozwiązaniem, które przychodzi mi do głowy, więc uruchamiasz tylko to, czego potrzebujesz, jest następujące: Używasz ngOnChanges do wykrycia właściwej zmiany
Używasz ngAfterViewChecked, aby faktycznie wymusić zmianę przed renderowaniem, ale po obliczeniu pełnej wysokości
Jeśli zastanawiasz się, jak zaimplementować scrollToBottom
źródło