Ionic2 loading a collection in an <ion-scroll>

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

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

1 Like

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...

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

1 Like

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

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.

1 Like

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.

1 Like

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...

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

1 Like

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]

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

{{ message | json }}
1 Like