Angular2: Change detection timing for an auto-scroll directive

别说谁变了你拦得住时间么 提交于 2019-12-06 19:31:34

Is there a way to better structure this code so that DOM will be updated then the Scroll function can be called?

The DOM should be updated before ngAfterViewChecked() is called. See if something like this works:

ngOnChanges(changes: {[propName: string]: SimpleChange}) {
    // detect the change here
    if (changes["inScrollHeight"] || changes["inClientHeight"]) {
        this.scrollAfterDomUpdates = true;
    }
};
ngAfterViewChecked() {
    // but scroll here, after the DOM was updated
    if(this.scrollAfterDomUpdates) {
       this.scrollAfterDomUpdates = false;
       this.scroll();
    }
}

If that doesn't work, try wrapping the call to scroll in a setTimeout:

    if(this.scrollAfterDomUpdates) {
       this.scrollAfterDomUpdates = false;
       this.setTimeout( _ => this.scroll());
    }

I found one way to solve this, it involves dividing the chat display into two separate components and use content projection. So there is a flow of changes from parent to child, and not having two functionalities in the same component with one triggering changes in the other. I can used the default changeDetectionStrategy without getting exceptions in dev mode.

@Component({
    selector: "chat-display",
    template: `
    <auto-scroll-display>
        <chat-message *ngFor="#chat of chats | async | messageFilter:username:inSelectedTarget:inTargetFilter:inDirectionFilter" [message]="chat.message" [type]="chat.type"></chat-message>
    </auto-scroll-display>
    `,
    directives: [NgClass, AutoScrollComponent, ChatMessageComponent],
    pipes: [AsyncPipe, MessageFilterPipe]
})
export class ChatDisplay implements OnInit { /* unchanged code */ }

The auto-scroll directive is identical to original post, was trying to figure out if there was a way to combine the directive functionality into the component. It's just acting as a container now.

@Component({
    selector: "auto-scroll-display",
    template: `
    <div #this class="chat-box" [inScrollHeight]="this.scrollHeight" [inClientHeight]="this.clientHeight" autoScroll>
        <ng-content></ng-content>
    </div>
    `,
    directives: [AutoscrollDirective]
})
export class AutoScrollComponent{ }

Here's a github link with working code, link.

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!