GSM85 GSM85 - 1 month ago 12
AngularJS Question

Cannot read property 'messages' of undefined

I am getting the following error when returning from a http service and attempting to push to response onto an array :

Cannot read property 'messages' of undefined


This is my chat.component.ts file :

import { Component, OnInit, OnDestroy } from '@angular/core';
import { ChatService } from './chat.service';

@Component({
selector: 'chat-component',
template: `
<div *ngIf="messages">
<div *ngFor="let message of messages">
{{message.text}}
</div>
</div>
<input [(ngModel)]="message" /><button (click)="sendMessage()">Send</button>
`,
providers: [ChatService]
})

export class ChatComponent implements OnInit, OnDestroy {
messages = [];
connection;
message;
loading;

constructor(private chatService: ChatService) { }

sendMessage() {
this.chatService.sendMessage(this.message);
this.message = '';
}

ngOnInit() {
this.chatService.initPlaylist().subscribe(tracks => {
tracks.forEach(function(item) {
this.messages.push({
message: item.trackID,
type: "new-message"
});
});
})

this.connection = this.chatService.getMessages().subscribe(message => {
this.messages.push(message);
})
}

ngOnDestroy() {
this.connection.unsubscribe();
}
}


This is my chat.service.ts

import { Injectable } from '@angular/core';
import { Http, Response } from '@angular/http';
import { Subject } from 'rxjs/Subject';
import { Observable } from 'rxjs/Rx';
import * as io from 'socket.io-client';
@Injectable()
export class ChatService {
private url = 'http://localhost:1337';
private socket;
constructor(private http: Http) {
}
sendMessage(message) {
this.socket.emit('add-message', message);
}
initPlaylist() {
return this.http.get(this.url + '/playlist')
.map(this.extratData)
.catch(this.handleError);
}
getMessages() {
let observable = new Observable(observer => {
this.socket = io(this.url);
this.socket.on('message', (data) => {
observer.next(data);
});
return () => {
this.socket.disconnect();
};
})
return observable;
}
private extratData(res: Response) {
let body = res.json();
return body || {};
}
private handleError(error: Response | any) {
// In a real world app, we might use a remote logging infrastructure
let errMsg: string;
if (error instanceof Response) {
const body = error.json() || '';
const err = body.error || JSON.stringify(body);
errMsg = `${error.status} - ${error.statusText || ''} ${err}`;
} else {
errMsg = error.message ? error.message : error.toString();
}
console.error(errMsg);
return Observable.throw(errMsg);
}
}


I currently have a form on the front end, in which users can add a message, this is then pushed onto
this.messages
and through socket.io sent out to all connected sockets.

What I am now doing is storing messages in a mongodb via an express app using mongoose.

On page load, I would like to retrieve these messages from the document store, and push them onto
this.messages
- so the view is updated with previous messages, then socket.io should take over on new messages, adding them to the array.

As this is an initial call, once on load, I am not using socket.io to grab these, instead I have an api route setup through express, returning json that looks as follows :

[
{
"_id": "58109b3e868f7a1dc8346105",
"trackID": "This is my message...",
"__v": 0,
"status": 0,
"meta": {
"played": null,
"requested": "2016-10-26T12:02:06.979Z"
}
}
]


However when I get to this section of code within
chat.component.ts
, everything breaks down with the previously mentioned error..

this.chatService.initPlaylist().subscribe(tracks => {
tracks.forEach(function(item) {
this.messages.push({
message: item.trackID,
type: "new-message"
});
});
})


I using Angular 2, Socket.io, ExpressJS and MongoDB.

Answer

don't use function () use instead () => (arrow function) for this.... to keep pointing to the local class instance

tracks.forEach((item) => {

https://developer.mozilla.org/en/docs/Web/JavaScript/Reference/Functions/Arrow_functions