最新消息:雨落星辰是一个专注网站SEO优化、网站SEO诊断、搜索引擎研究、网络营销推广、网站策划运营及站长类的自媒体原创博客

javascript - Angular: unable to scroll down to bottom in element - Stack Overflow

programmeradmin3浏览0评论

I've been postponing fixing this error that I have been having for a while now. I have the below chatwindow:

The window where I display the messages is a separate ponent (chat-windowponent.ts). I want to scroll to the bottom with ngOnChanges.

When we receive the conversation with the messages from the parent ponent, where it is received from the server via an asynchronous request, we want to scroll to the bottom of the window element. We do this by calling the this.scrollToBottom() method of the class in the ngOnChanges lifecycle hook.

This.scrollToBottom does get called, but it doesn't scroll to the bottom of the element. Can someone see why?

chat-windowponent.ts: in ngOnchanges we do some synchronous stuff before we call this.scrollToBottom()

export class ChatboxWindowComponent implements OnChanges, OnInit, AfterViewChecked {

  @Input('conversation') conversation;
  @ViewChild('window') window;

  constructor() { }

  ngOnChanges() {
    // If the date separators have already been added once, we avoid doing it a second time
    const existingDateObj = this.conversation.messages.findIndex((item, i) => item.dateObj);

    if (existingDateObj === -1) {
      this.conversation.messages.forEach( (item, index, array) => {
        if (index !== 0) {
          const date1 = new Date(array[index - 1].date);
          const date2 = new Date(item.date);

          if (date2.getDate() !== date1.getDate() || date2.getMonth() !== date1.getMonth()) {
            this.conversation.messages.splice(index, 0, {date: date2, dateObj: true});
            console.log(this.conversation.messages.length);
          }
        }
      });
    }

    this.scrollToBottom();
  }

  ngOnInit() {
  }

  ngAfterViewChecked() {
  }

  isItMyMsg(msg) {
    return msg.from._id === this.conversation.otherUser.userId;
  }

  scrollToBottom() {
    try {
      console.log('scrollToBottom called');
      this.window.nativeElement.top = this.window.nativeElement.scrollHeight;
    } catch (err) {}
  }
}

chat-windowponent.html

<div #window class="window">
  <ng-container *ngFor="let message of conversation.messages">
    <div class="date-container" *ngIf="!message.msg; else windowMsg">
      <p class="date">{{message.date | amDateFormat:'LL'}}</p>
    </div>
    <ng-template #windowMsg>
      <p
        class="window__message"
        [ngClass]="{
    'window__message--left': isItMyMsg(message),
    'window__message--right': !isItMyMsg(message)
    }"
      >
        {{message.msg}}
      </p>
    </ng-template>
  </ng-container>
</div>

I've been postponing fixing this error that I have been having for a while now. I have the below chatwindow:

The window where I display the messages is a separate ponent (chat-window.ponent.ts). I want to scroll to the bottom with ngOnChanges.

When we receive the conversation with the messages from the parent ponent, where it is received from the server via an asynchronous request, we want to scroll to the bottom of the window element. We do this by calling the this.scrollToBottom() method of the class in the ngOnChanges lifecycle hook.

This.scrollToBottom does get called, but it doesn't scroll to the bottom of the element. Can someone see why?

chat-window.ponent.ts: in ngOnchanges we do some synchronous stuff before we call this.scrollToBottom()

export class ChatboxWindowComponent implements OnChanges, OnInit, AfterViewChecked {

  @Input('conversation') conversation;
  @ViewChild('window') window;

  constructor() { }

  ngOnChanges() {
    // If the date separators have already been added once, we avoid doing it a second time
    const existingDateObj = this.conversation.messages.findIndex((item, i) => item.dateObj);

    if (existingDateObj === -1) {
      this.conversation.messages.forEach( (item, index, array) => {
        if (index !== 0) {
          const date1 = new Date(array[index - 1].date);
          const date2 = new Date(item.date);

          if (date2.getDate() !== date1.getDate() || date2.getMonth() !== date1.getMonth()) {
            this.conversation.messages.splice(index, 0, {date: date2, dateObj: true});
            console.log(this.conversation.messages.length);
          }
        }
      });
    }

    this.scrollToBottom();
  }

  ngOnInit() {
  }

  ngAfterViewChecked() {
  }

  isItMyMsg(msg) {
    return msg.from._id === this.conversation.otherUser.userId;
  }

  scrollToBottom() {
    try {
      console.log('scrollToBottom called');
      this.window.nativeElement.top = this.window.nativeElement.scrollHeight;
    } catch (err) {}
  }
}

chat-window.ponent.html

<div #window class="window">
  <ng-container *ngFor="let message of conversation.messages">
    <div class="date-container" *ngIf="!message.msg; else windowMsg">
      <p class="date">{{message.date | amDateFormat:'LL'}}</p>
    </div>
    <ng-template #windowMsg>
      <p
        class="window__message"
        [ngClass]="{
    'window__message--left': isItMyMsg(message),
    'window__message--right': !isItMyMsg(message)
    }"
      >
        {{message.msg}}
      </p>
    </ng-template>
  </ng-container>
</div>
Share Improve this question edited Nov 2, 2018 at 18:24 tilly asked Nov 2, 2018 at 18:19 tillytilly 2,61010 gold badges42 silver badges73 bronze badges 10
  • I forgot to add the template. Up in a second – tilly Commented Nov 2, 2018 at 18:23
  • 2 Try using scrollTop instead of top like so this.window.nativeElement.scrollTop = this.window.nativeElement.scrollHeight – Suryan Commented Nov 2, 2018 at 18:28
  • I edited it. It didn't solve the problem. I did 4 console.logs to see what they gave me. I did two (of scrollTop and scrollheight) before I did this.window.nativeElement.scrollTop = this.window.nativeElement.scrollHeight and two after. The results before were scrollTop is 0 and scrollHeight is 229. – tilly Commented Nov 2, 2018 at 18:40
  • 1 For a test: does it work if you scroll after a delay: setTimeout(() => { this.scrollToBottom(); }, 500);? – Martin Parenteau Commented Nov 2, 2018 at 18:43
  • 1 Hope this link would help you out stackoverflow./questions/35232731/… – Suryan Commented Nov 2, 2018 at 18:45
 |  Show 5 more ments

4 Answers 4

Reset to default 9

The scroll doesn't work because the list of messages is not rendered yet when you call scrollToBottom. In order to scroll once the messages have been displayed, set a template reference variable (e.g. #messageContainer) on the message containers:

<ng-container #messageContainer *ngFor="let message of conversation.messages">
  ...
</ng-container>

In the code, you can then access these elements with ViewChildren and scroll the window when the QueryList.changes event is triggered:

@ViewChildren("messageContainer") messageContainers: QueryList<ElementRef>;

ngAfterViewInit() {
  this.scrollToBottom(); // For messsages already present
  this.messageContainers.changes.subscribe((list: QueryList<ElementRef>) => {
    this.scrollToBottom(); // For messages added later
  });
}

You can add the following code into your HTML element.

#window [scrollTop]="window.scrollHeight" *ngIf="messages.length > 0"

Full code according to your code sample as follows,

<div #window [scrollTop]="window.scrollHeight" *ngIf="messages.length > 0" class="window">
  <ng-container *ngFor="let message of conversation.messages">
    <div class="date-container" *ngIf="!message.msg; else windowMsg">
      <p class="date">{{message.date | amDateFormat:'LL'}}</p>
    </div>
    <ng-template #windowMsg>
      <p
        class="window__message"
        [ngClass]="{
    'window__message--left': isItMyMsg(message),
    'window__message--right': !isItMyMsg(message)
    }"
      >
        {{message.msg}}
      </p>
    </ng-template>
  </ng-container>
</div>

This is work for me. (Currently, I'm using Angular 11)

发布评论

评论列表(0)

  1. 暂无评论