4

In my Nativescript Angular application, I have a TextView within a ScrollView, defined as such:

<ScrollView orientation="vertical" height="70%" width="100%" style="margin-bottom: 1%; background-color:white" (loaded)="onScrollerLoaded($event)">
    <TextView 
        id="terminal" [text]="terminalText" editable="false"
        style="color: whitesmoke; background-color: black; font-size: 8%; font-family: monospace" height="100%"     
        (tap)="onTap($event)" (loaded)="onTerminalLoaded($event)">
    </TextView>
</ScrollView>

The purpose of this element is to act as a terminal, and is rapidly printing incoming messages from a bluetooth device.

Currently, the ScrollView is scrolling back to the top whenever I add some text to the terminalText variable, to which the TextView is bound. I would like to be able to keep the ScrollView at the bottom of the TextView.


A few notes:

I am adding text to the terminalText variable within my associated component class through this method:

public appendToTerminal(appendStr){
    this.terminalText += appendStr;
}

I have tried implementing the following code that would execute once the ScrollView loads:

private scrollIntervalId;
onScrollerLoaded(data: EventData){
    if(!this.scrollIntervalId){
        this.scrollIntervalId = setInterval(()=>{
            this.ngZone.run(() =>
                (data.object as any).scrollToVerticalOffset((data.object as any).scrollableHeight, false)
            )
        }, 10);
    }
}

(This attempt is based on an explanation given here

I have only tried this on an Android device, as I do not have access to an Apple device.

2
  • on scrollview load it is working or not? Commented Jul 5, 2018 at 7:38
  • @bhavinjalodara It's working Commented Jul 5, 2018 at 19:41

2 Answers 2

10

you are setting TextView to fixed height 100% which is will be same as ScrollView that is why scrollableHeight will always be 0. you should use minHeight="100%".

then you can scroll programmatically to the end when you are appending text to terminal text this.terminalText += appendStr.

like this

public appendToTerminal(appendStr){
    this.terminalText += appendStr;
    setTimeout(()=>{
        scrollView.scrollToVerticalOffset(scrollView.scrollableHeight, false);

    },150);
}

this will append the text then get the scrollableHeight and then will scroll to it.

here is working playground demo:https://play.nativescript.org/?template=play-ng&id=Rs0xnP&v=16

Sign up to request clarification or add additional context in comments.

7 Comments

Tried your method, still doesn't work. I may have found the reason why - I logged the values of scrollView and it's scrollableHeight and while scrollView is good, scrollableHeight is set to 0 at all times, even when I can manually scroll down the page. Any comment on this? I tried embedding the TextView in a StackLayout, but no luck there either.
can you create the playground demo. then i can have a look.
In case anyone get still 0 as scrollableHeight. I am not sure why, but without setTimeout it is not working. Handling the scrollable things in a setTimeout cb function solves the issue.
you can also try running this in NgZone.
|
-1

The function below can only be used in the Angular ngDoCheck() or ngAfterContentChecked() lifecycle:

// See https://angular.io/guide/lifecycle-hooks
function goDownScrollView(scrollView: object, animate: boolean = true): boolean {

    let neScrollView:     ScrollView = <ScrollView>getNativeElement(scrollView),
        scrollableHeight: number     = neScrollView.scrollableHeight;

    console.log("neScrollView:", neScrollView);
    console.log("neScrollView scrollableHeight:", scrollableHeight);

    if (scrollableHeight > 0) {

        neScrollView.scrollToVerticalOffset(scrollableHeight, animate);
        return true;

    } else {

        return false;

    }

}

An helper to always get the native element:

function getNativeElement(object: object): object {

    return (object.hasOwnProperty("nativeElement")) ? object['nativeElement'] : object;

}

The scrollable height may be zero at the first pass of the lifecycle (for example, if you add elements to your ScrollView with an HTTP request). That's why you have to test the current content with new before scroll:

// See https://angular.io/api/core/ViewChild
@ViewChild("content") private _pageContent: ElementRef<ScrollView>;

public  currentContent:   object;
private _previousContent: object;

...

ngAfterContentChecked(): void {

    if (this.currentContent != this._previousContent) {

        let isScrollDown: boolean = goDownScrollView(this._pageContent);

        if (isScrollDown) {

            this._previousContent = this.currentContent;

        }

    }

}

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.