1

I'm using a for in to loop over a list of Meeting-objects called allMeetings. This loop is filling another list called allEvents, where objects other than Meeting will end up in. In that loop I'm trying to get the properties of the Meeting object, but they aren't recognised. I wonder how to solve or bypass it.

My Meeting model:

export class Meeting {
    id: UUID;
    date: Date;
    description: string;
}

The TS-File:
The loop is used in the makeEvents() method

...
import { Meeting } from '../models/meeting.model';
import { MeetingsService } from '../services/meetings.service';
...
export class SomeComponent implements OnInit {
    allEvents: SpikesEvent[] = undefined;
    allMeetings: Meeting[] = undefined;

   constructor(private _meetingsService: MeetingsService) { }

    ngOnInit() {
        this.loadMeetings();
        this.makeEvents();
    }

    loadMeetings(): void {
        this._meetingsService.getAllMeetings().subscribe(
            (allMeetings: Meeting[]) => {
                this.allMeetings = allMeetings;
            }
        );
    }

    makeEvents(): void {
        for (let meeting in this.allMeetings) {
            this.allEvents.push({
                start: startOfDay(meeting.date),
                title: meeting.description,
                color: colors.yellowsunflower,
                type: "meeting",
                id: meeting.id,
            });
        }
    }
}

So, date, description and id of meeting aren't recognised.

EDIT 1: Added the constructor in the TS-File.
EDIT 2: I'm retrieving my data from rethinkDB so there's no JSON-file but here's a log to prove that the Meeting object is in fact not empty:

date: "Fri Feb 20 1993 00:00:00 GMT+00:00", description: "meeting about dummy data", id: "088c0baf-3c02-48b2-a072-65905fb0c0a7"
Wouter Vanherck
  • 2,070
  • 3
  • 27
  • 41
  • makeEvents() is called before loadMeetings() has finished running. So you dont have the data inside allMeetings object within makeEvents() – Amit Chigadani Apr 03 '17 at 13:17
  • 1
    Possible duplicate of [How do I return the response from an asynchronous call?](http://stackoverflow.com/questions/14220321/how-do-i-return-the-response-from-an-asynchronous-call) – Andreas Apr 03 '17 at 13:18
  • 1
    Possible duplicate of [How do I return the response from an Observable/http/async call in angular2?](http://stackoverflow.com/questions/43055706/how-do-i-return-the-response-from-an-observable-http-async-call-in-angular2) – eko Apr 03 '17 at 13:19
  • @Amit Chigadani - It's true that I still have to think about asynchronous programming when executing my code but the problem is that I can't read the property's of the Meeting-object. – Wouter Vanherck Apr 03 '17 at 13:19
  • 1
    @WouterVanherck that's because `meeting` is `undefined` inside `makeEvents` method. Check the links to find out why. – eko Apr 03 '17 at 13:22
  • Yes you won't, because you have not injected the Meeting class in your component. Add this `constructor(private allMeetings: Meeting){}`. Add all the dependency injections properly. I might have missed few here. – Amit Chigadani Apr 03 '17 at 13:25
  • @Amit Chigadani - Whoops, forgot to include it in the question (but it was in my code) – Wouter Vanherck Apr 03 '17 at 13:32
  • Can you share your `allmeetings` json. – Aakash Thakur Apr 03 '17 at 13:35

3 Answers3

2

Change your code to this

ngOnInit() {
    this.loadMeetings();
}

loadMeetings(): void {
    this._meetingsService.getAllMeetings().subscribe(
        (allMeetings: Meeting[]) => {
            this.allMeetings = allMeetings;
            // you should call this function once 
            // we get the data in this.allMeetings
            this.makeEvents();
        }
    );
}
Vivek Doshi
  • 56,649
  • 12
  • 110
  • 122
  • I'm sorry if my question isn't clear enough. I'm not yet thinking about asynchronous programming and am just wondering why typeScript doesn't recognise the properties. Or are these related? – Wouter Vanherck Apr 03 '17 at 13:21
  • 2
    @Wouter Vanherck Yes they are related, declaring an object with some class will not give you the prototype of the class itself. So definitely meeting variable within for loop will be undefined, because allMeetings object itself will be undefined before your observable returns – Amit Chigadani Apr 03 '17 at 13:38
  • Tried it the way you did but that didn't change the fact that `Property 'id' does not exist on type 'string'` came up, including the errors for the other properties. – Wouter Vanherck Apr 03 '17 at 13:56
  • in Meeting class change id:number to string or change this id: parseInt (meeting.id). – Vivek Doshi Apr 03 '17 at 14:01
  • @VivekDoshi a [UUID](https://en.wikipedia.org/wiki/Universally_unique_identifier#Format) is represented as a string so don't worry about changing it. – Wouter Vanherck Apr 04 '17 at 06:29
2

Funny, everyone has missed the fact that you are iterating a list of objects with for ...in and trying to use the key as the object itself.

That is why TypeScript "won't recognize" it's properties. If you want to use for-in:

for (let meeting in this.allMeetings) {
    this.allEvents.push({
        start: startOfDay(this.allMeetings[meeting].date),
        //...
    });
}

I'd rather use forEach.

The other answer about the asynchronous code is still valid for runtime execution though, but that is not the problem you are asking about here.

Alex
  • 14,104
  • 11
  • 54
  • 77
1

You need to manipulate the data inside the callback, like suggested. Here's a useful question to look at: How do I return the response from an Observable/http/async call in angular2?

As also mentioned you are using the key as the object instead, as suggested, use forEach instead. So first execute loadMeetings and inside the callback call makeEvents:

ngOnInit() {
    this.loadMeetings();
}

loadMeetings(): void {
   this._meetingsService.getAllMeetings()
     .subscribe((allMeetings: Meeting[]) => {
         this.allMeetings = allMeetings;
            this.makeEvents();
        });
}

Then your makeEvents would look like this:

makeEvents(): void {
  this.allMeetings.forEach((x:Meeting) => {
     this.allEvents.push({
       start: startOfDay(x.date),
       title: x.description,
       color: colors.yellowsunflower,
       type: "meeting",
       id: x.id,
     })
  })
}

Then it should work as you want, here's a

Demo

Community
  • 1
  • 1
AT82
  • 71,416
  • 24
  • 140
  • 167
  • 1
    By elaborating @Alex 's answer on how to use the foreach you've helped me, thanks for that. – Wouter Vanherck Apr 04 '17 at 06:50
  • 1
    No problem! Wanted to just lift up the issue that your `allMeetings` would be undefined/empty at the point when you try and execute `makeEvents` as your code sits now, which would cause additional issue. But yes, that was not perhaps your main question at hand. Most important you got a solution for your problem :) Have a great day and happy coding! :) – AT82 Apr 04 '17 at 07:58