Search code examples
listviewnativescriptscrollview

ListView istead of *ngFor


I use a ScrollView for a Chat-Overview in NativeScript.

I used this code for the Scrollview until now:

<ScrollView #scrollLayout style="height: 80%;margin-top: -200px">

   <StackLayout class="chat-body">
        <StackLayout *ngFor="let message of messages"  orientation="vertical">

                <Label *ngIf="message.sender == me" horizontalAlignment="right" class="chat-message-me" [text]="message.msg"></Label>
                <Label *ngIf="message.sender == me" horizontalAlignment="right" class="chat-timestamp" [text]="message.time"></Label>
            
                <Label *ngIf="message.sender != me" horizontalAlignment="left" class="chat-message-you" [text]="message.msg"></Label>
                <Label *ngIf="message.sender != me" horizontalAlignment="left" class="chat-timestamp" [text]="message.time"></Label>
        
        </StackLayout> 
    </StackLayout>

</ScrollView>

It worked, but when i added a new element to the messages array the view would load the complete array on top of the already showing array.

Message Array:

![```

View of Chat:

enter image description here

So my Solution was to use a ListView, like this:

<ScrollView #scrollLayout style="height: 80%;margin-top: -200px">
    <GridLayout class="chat-body">
        <ListView [items]="messages" orientation="vertical">
            <ng-template let-item="message">
                
                <Label *ngIf="message.sender == me" horizontalAlignment="right" class="chat-message-me" [text]="message.msg"></Label>
                <Label *ngIf="message.sender == me" horizontalAlignment="right" class="chat-timestamp" [text]="message.time"></Label>
            
                <Label *ngIf="message.sender != me" horizontalAlignment="left" class="chat-message-you" [text]="message.msg"></Label>
                <Label *ngIf="message.sender != me" horizontalAlignment="left" class="chat-timestamp" [text]="message.time"></Label>

                
            </ng-template>
        </ListView>
   </GridLayout>
</ScrollView>

But i get this Error:

System.err: An uncaught Exception occurred on "main" thread.
System.err: Calling js method getView failed
System.err: Error: No suitable views found in list template! Nesting level: 0
System.err:

Solution

  • A ListView automatically scrolls, so you shouldn't need a ScrollView parent.

    The error you are seeing is because the ListView requires a single component/layout inside it (where you have the 4 labels).

    To fix the error you could wrap your labels inside a ContentView or a layout like so:

    <ListView [items]="messages" orientation="vertical">
      <ng-template let-message="item">
        <ContentView>
          <Label *ngIf="message.sender == me" horizontalAlignment="right" class="chat-message-me" [text]="message.msg"></Label>
          <Label *ngIf="message.sender == me" horizontalAlignment="right" class="chat-timestamp" [text]="message.time"></Label>      
          <Label *ngIf="message.sender != me" horizontalAlignment="left" class="chat-message-you" [text]="message.msg"></Label>
          <Label *ngIf="message.sender != me" horizontalAlignment="left" class="chat-timestamp" [text]="message.time"></Label>
        </ContentView>
      </ng-template>
    </ListView>
    

    However, using ngIfs inside a ListView has some performance impacts. If possible, use multiple item templates instead. This blog post has some indepth comparison between the two approaches.