1

のための変化検出タイミング:Angular2:私はチャット表示するための簡単な自動スクロールの指示に取り組んできました自動スクロールディレクティブ

@Directive({ 
    selector: "[autoScroll]" 
}) 
export class AutoScroll { 
    @Input() inScrollHeight; 
    @Input() inClientHeight; 

    @HostBinding("scrollTop") outScrollTop; 

    ngOnChanges(changes: {[propName: string]: SimpleChange}) { 
     if (changes["inScrollHeight"] || changes["inClientHeight"]) { 
      this.scroll(); 
     } 
    }; 

    scroll() { 
     this.outScrollTop = this.inScrollHeight - this.inClientHeight; 
    }; 
} 

は、このディレクティブは、私が設定したときに動作しますenableProdMode()とするときChangeDetectionStrategyはデフォルトに設定されていますが、「devモード」では例外が発生します。 ChangeDetectionStrategyonPushに設定することができます。その場合、例外は発生しませんが、スクロールは遅れます。

Domを更新してからScroll関数を呼び出すことができるように、このコードを構造化する方法はありますか?私はsetTimeout()を試しましたが、遅延が悪化し、ChangeDetectorRefを使って試してみて、observableを購読してmarkForCheck()をトリガーしました。 ngAfterViewChecked()を使用すると、ブラウザがクラッシュします。

@Component({ 
    selector: "chat-display", 
    template: ` 
      <div class="chat-box" #this [inScrollHeight]="this.scrollHeight" [inClientHeight]="this.clientHeight" autoScroll> 
       <p *ngFor="#msg of messages | async | messageFilter:username:inSelectedTarget:inTargetFilter:inDirectionFilter" [ngClass]="msg.type">{{msg.message}}</p> 
      </div> 
     `, 
    styles: [`.whisper { 
      color: rosybrown; 
     }`], 
    directives: [NgClass, AutoScroll], 
    pipes: [AsyncPipe, MessageFilterPipe], 
    changeDetection: ChangeDetectionStrategy.OnPush 
}) 
export class ChatDisplay implements OnInit { 

    username: string; 
    @Input() inSelectedTarget: string; 
    @Input() inTargetFilter: boolean; 
    @Input() inDirectionFilter: boolean; 

    messages: Observable<ChatType[]>; 

    constructor(private socketService_: SocketService, private authService_: AuthService) { 
     this.username = this.authService_.username; 
    }; 

    ngOnInit() { 
    } 

} 

これは、DEVモードで起動される例外です。

例外:式 '1 @ ChatDisplayでthis.scrollHeight:40には、' それが確認した後に変更されました。以前の値: '417'現在値: '420' [this.scrollHeight ChatDisplay 1 @:40]で angular2.dev.js(23083,9)

+0

は「例外」が実際には何か興味深いものになるだろう。 –

+0

devモードで変更検出が2回発生し、チェックの間に "this.scrollHeight"という表現が異なります。観察可能なメッセージがディスプレイに表示されているように、これはscrollHeightを増加させるので、それはチェックの間で異なります、私はそれが起こっていると思います。 – dppower

+0

質問に正確なエラーメッセージを追加できますか? –

答えて

2

私はそれが中にチャット表示を分割することを含む、この問題を解決する一つの方法を発見しました2つの別々のコンポーネントとコンテンツの投影を使用します。したがって、親から子への変更の流れがあり、同じコンポーネント内に2つの機能がなく、一方のコンポーネントが他方のコンポーネントの変更をトリガーします。 devモードで例外を受け取らずにデフォルトのchangeDetectionStrategyを使用できます。

@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 */ } 

オートスクロール命令はオリジナルの機能と同じですが、命令機能をコンポーネントに組み込む方法があるかどうかを判断しようとしていました。それはちょうど今コンテナとして機能しています。

@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{ } 

ここに、作業コードのギブスリンクlinkがあります。

2

DOMが更新されてからスクロール機能が呼び出されるように、このコードを構造化する方法はありますか?

ngAfterViewChecked()が呼び出される前にDOMを更新する必要があります。このような何かが動作するかどうかを参照してください。問題が解決しない場合は

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(); 
    } 
} 

は、setTimeoutメソッドでスクロールする呼び出しをラップしてみてください。

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

ちょっと試してみましたが、変更検出のラウンド間でプロパティバインディングが変わることについては例外があります。私は行って、働くようなものを手に入れようとしている簡単なプロジェクトを作った[http://github.com/dppower/angular2-autoscroll/tree/testing2]。以下は、あなたが提案している行に沿ったコンテンツ投影による実装です。[link](http://github.com/dppower/angular2-autoscroll/tree/testing1)。 – dppower

関連する問題