2

After toying with Angular 2 using strictly static content, I ventured into HTTP/Observable land to see what came of it. Observables are a nice alternative to Promises - although the benefits when compared to that alternative are lost on me for now. But there is one problem that's been puzzling me this afternoon.

When fetching data using Observables (as per https://angular.io/docs/ts/latest/guide/server-communication.html), it seems the class corresponding to the model is not loaded. This is not a problem as long as only properties are used, but it prevents using methods that can be defined inside that class.

Plunker : http://plnkr.co/edit/WjEfdOHmHWT2RZVDSkjr?p=preview

You can materialize the problem by alternating between the two instructions defined in ngOnInit() in the App component:

ngOnInit(){

  // NB
  // Alternate between the two instructions below while checking
  // the 'Network' tab of your devtool of choice.

  // Doing this will actually load the 'person.model.ts' file,
  // and make the methods available to the component and its template
  this.people[0] = new Person();

  // Doing this will NOT load the 'person.model.ts' file, thus
  // causing any call to a method defined in that class to fail.
  //this.getPeople();
}

When the first instruction is used, the method person.greet() works just fine when called via interpolation in the template, and the corresponding file is fetched. But when using the second instruction, an error is raised and logged to the console. By the way this error appears on the Plunker I made - I get nothing when met with the problem on my own application.

Now it is probably possible to bypass the problem (for example, making a dummy call to new Person() before the subscription kicks in), but this does feel really clumsy. Something similar is suggested here : https://stackoverflow.com/a/34777339/5751783 (although I'm not completely sure that SO question is related).

Is this a real problem, or am I doing something wrong ? And if there is indeed an issue at hand, what would be the proper way of preventing it ?

Thanks in advance !

Disclaimer : if there is an actual issue, I'm not sure if it's related to Angular2, SystemJS, RxJS or some other component used under the hood. I'll use the tag angular2 for the time being (given that's the reason I'm here), but I'll add more (or remove angular2) depending on the answers.

Community
  • 1
  • 1
phl
  • 342
  • 3
  • 14

1 Answers1

1

In fact when you can the result of the request to Person[], it's not really converted to objects of type Person.

To achieve this you need to instantiate explicitly the Person class for each element in the list:

return this.http.get(this._personUrl)
            .map(res => <Person[]> res.json())
            .map(people => {
              return people.map((person) => {
                return new Person(person.firstName, person.surname);
              });
            })
            .catch(this.handleError);

This way you will be able to use methods of the Person class.

See this question for more details:

Community
  • 1
  • 1
Thierry Templier
  • 198,364
  • 44
  • 396
  • 360
  • Thanks for the explanation ! This would definitely explain the problem - I mistook `` for a type casting, which it apparently isn't ! This being said, I think I might need some more help. I tried adding the second `map()` operation you described in the Plunker, but the issue remains. It's probably not much, but it's not working at the moment. I'll look into it myself and comment again if I find something. Ideally, I'm looking for a service-contained solution, not something to add in the component. – phl Mar 30 '16 at 07:47
  • You're welcome! What do you exactly mean by the problem remains? Do you receive an array with instances of type `Person` when subscribing? – Thierry Templier Mar 30 '16 at 08:09
  • My bad, I still have a problem, but it might not be the same ! When adding the `map()` in the service, the file `person.model.ts` is now loaded. In this regard, the original problem can be considered solved. But an error is still raised when the method `greet()` is called. I tampered with the Plunker to add a break point, and the array I get when the subscribe is reached is not typed. The error is : `TypeError: l_person0.greet is not a function`, which is probably related to our typing issue. – phl Mar 30 '16 at 08:30
  • 1
    Okay, it was indeed nothing much : the `map()` function does not alter the original array. Instead of `return people;` in your code sample, everything works just fine when returning `people.map(...)`. Thanks again :) – phl Mar 30 '16 at 08:35