Ionic2 loading a collection in an <ion-scroll>


#1

Hi All,

I am using Ionic 2, and am trying to load a collection of messages in an <ion-scroll>. My problem is, that the html tries to render the message items before they are ready I think. As a result, I get the following error:

As you can see, the message item is undefined.

Exception in queued task: EXCEPTION: Error in build/pages/messages/messages.html:65:9
ORIGINAL EXCEPTION: TypeError: Cannot read property 'ownership' of undefined
ORIGINAL STACKTRACE:
TypeError: Cannot read property 'ownership' of undefined
    at DebugAppView._View_MessagesPage6.detectChangesInternal (MessagesPage.template.js:1062:70)

However, it does in fact render. I think this is due to the message item being populated after.

html

<ion-content padding class="messages-page-content">
	<ion-scroll scrollY="true" class="messages">

		<div *ngFor="let message of messages" class="message-wrapper">
				<div *ngIf="message.changeDate">
					<center><span class="message-datetime">{{message.createdAt | amDateFormat: 'DD MMM YYYY'}}</span></center>
				</div>
				<div [class]="'message message-' + message.ownership">
					<div class="message-content">local:{{message.content}}</div>
					<span class="time-tick">
        <span class="message-timestamp">{{message.createdAt | amDateFormat: 'h:mm a'}}</span>
					<div *ngIf="message.readByReceiver && senderId == message.senderId">
						<span class="checkmark">
              <div class="checkmark_stem"></div>
              <div class="checkmark_kick"></div>
          </span>
					</div>
					</span>
				</div>
		</div>
	</ion-scroll>
</ion-content>

ts

private messages: Mongo.Cursor<Message>;

        this.messages = Messages.find({
          chatId: this.activeChat._id
        }, {
            sort: { createdAt: 1 },
            transform: this.transformMessage.bind(this)
          });

Question

Is it possible to only let the html start to load the collection when it is ready? Or, is the perhaps something else I am doing wrong? Why would it try iterate through the collection when its objects are still undefined?

Thank you


#2

maybe use an async pipe for this? so let message of messages | async


#3

Thanks luukschoen. That didn’t work for me, it just cases nothing to render, does not iterate through the list.

I have changed the code to output “loading...” if there message item is undefined. And it does display “loading...” on the screen, implying that message is undefined. But I also log the output from !exists(message), and it indicates that message is not undefined. So it looks like the html is not in agreement with the ts.

html

	<div *ngFor="let message of messages" class="message-wrapper">
		<div *ngIf="!exists(message)">
			<div *ngIf="message.changeDate">
				<center><span class="message-datetime">{{message.createdAt | amDateFormat: 'DD MMM YYYY'}}</span></center>
			</div>
			<div [class]="'message message-' + message.ownership">
				<div class="message-content">local:{{message.content}}</div>
				<span class="time-tick">
    <span class="message-timestamp">{{message.createdAt | amDateFormat: 'h:mm a'}}</span>
				<div *ngIf="message.readByReceiver && senderId == message.senderId">
					<span class="checkmark">
          <div class="checkmark_stem"></div>
          <div class="checkmark_kick"></div>
      </span>
				</div>
				</span>
			</div>
		</div>
		<div *ngIf="!message">
			<p>loading...</p>
		</div>
	</div>

ts

  public exists(message: Message): boolean {
    console.log('exists: message = '+message.content+',   exists = '+(this.localMessageIds.indexOf(message._id) > -1));
    if (message) {
      return this.localMessageIds.indexOf(message._id) > -1;
    }
    true;
  }

output:

exists: message = test, exists = false

You can see that the message item is not undefined as it has a content of “test”. But the screen displays:

loading...


#4

I didn’t read the topic properly yet… I missed the above error. That means ownership doesnt exist on the message, but it doesn’t mean the message is undefined. Can you try to prefix ownership with a questionmark like this, so instead of using message.ownership doing this: message?.ownership


#5

Thanks, I will give that a try. But it still does not explain why loading... is being outputted (that’s when !message)


#6

What also would be an option is to just render the messages only if the length is greater then 0. In other words, don’t do this: *ngIf="!exists(message)" but just check for the length of the array right away: *ngIf=“messages.length > 0” . Now you’re sure everything inside is only called when the expression says the messages length is greater then zero.


#7

This just means what you probably already figured out yourself, that the variable messages is not really empty. Using the ! operator just queries for not message over here. I assume (assumption(!)) that message is not empty, but so that’s why it says loading. If you want to know if message == null, you could use the double not operator !!message like that.


#8

Very strange. I am testing using:

		<div *ngIf="message == null">
			<p>loading...</p>
		</div>

The console output shoes that message is not null.

exists: message = test3, exists = false

But I still get:

loading...


#9

just check bij using *ngIf="!!message". Did you try the solution with the length operator?


#10

It doesn’t display anything inside the:

<div *ngIf="messages.length > 0"> ... </div>

Previously it was before I put the check in place.

To me, this suggests it is a timing issue. The html is trying to loop before the messages are populated. It is iterating though, because I have this outside the if statement:

		<div *ngIf="!!message">
			<p>loading...{{messages.length}} and {{message}}</p>
		</div>

and it outputs:

loading... and [object Object]


#11

If you want to directly display the message, wrap it and pipe it (its probably json) do this:

{{ message | json }}