1

I am working in Angular and I have a following situation:

my.service.ts has this class:

export class MyClass {
    MyList: string[] = [];
    MyString: string = '';

    createString(): void {
        this.MyList.forEach(s => {
            this.MyString += s + ', ';
        });
    }
}

And my.component.ts calls it like this:

myData: MyClass[] = [];

this.myService.getMyData().subscribe(res => {
    myData = res;
    if (myData.length > 0) {
        this.myData.forEach(x => x.createString());
    }
});

VS Code recognizes the createString function as a metod of MyClass, but I still get an error:

ERROR TypeError: x.createString is not a function

Any explanations?

EDIT: The data comes from back end, and the back end model doesn't have this method. Maybe that is the issue?

dzenesiz
  • 1,388
  • 4
  • 27
  • 58
  • 1
    If you are transfering using JSON, you are only transfering data, not methods or classes. You need to have code that will reify JSON as your class. Without it... TS believes `x` should be a `MyClass`, so VSCode lets you do completion; but `x` is in actuality probably just a POJO. – Amadan May 21 '19 at 08:17
  • 1
    The issue would be that the response you get is not your class objects, they are normal Javascript objects, create instances first – Ashish Ranjan May 21 '19 at 08:17
  • See https://github.com/angular/angular/issues/25401 – jonrsharpe May 21 '19 at 08:18
  • 1
    Possible duplicate of [No methods in http response object](https://stackoverflow.com/questions/48102824/no-methods-in-http-response-object) – jonrsharpe May 21 '19 at 08:24
  • @jonrsharpe reading this question and answers I realize that, yes, it is the same problem. – dzenesiz May 21 '19 at 08:30
  • 1
    Also note that checking `myData.length > 0` is pointless - if it's an empty array it'll just loop over zero things, and if it's not an array the check will likely fail to find a length property. – jonrsharpe May 21 '19 at 08:30
  • @jonrsharpe seeing all this, I think I'll build that string on the server side. That way, I'll have to check nothing at all. – dzenesiz May 21 '19 at 08:32
  • 1
    @jonrsharpe it's not just the `length` check - there is a lot of unnecessary code. The `forEach` in `createString` can just be replaced with `this.MyList.join(", ")` and the `forEach` for calling `createString` also strikes me as unnecessary - the `string` property could just have a dynamic getter that builds the the value on demand and caches it, instead of having to call an extra method to populate it on each element and each time the observable pushes an update. – VLAZ May 21 '19 at 08:37
  • @VLAZ well, I was trying to piece together a rough illustration of the problem, not optimize the code. If you comment on every single line, you'd have to say that naming is a bit fishy, right? :) The final code is significantly different, but that was not the point of this question. Nevertheless, you are completely right about unnecessary code. – dzenesiz May 22 '19 at 13:22

2 Answers2

5

The object coming from the server will be just a simple object not an instance of the class MyClass. You can create instances of MyClass and assign the values from the server object to the instance of the class:

this.myService.getMyData().subscribe(res => {
    myData = res.map(o => Object.assign(new MyClass(), o));
    if (myData.length > 0) {
        this.myData.forEach(x => x.createString());
    }
});
Titian Cernicova-Dragomir
  • 230,986
  • 31
  • 415
  • 357
0

Accepted soulution didn't help me, so I propose mine. It does not require .map().

My http service:

getOffers() {
    return this.http.get('https://ohipo.pl/assets/oferty.json');
  }

Consuming service in component:

offers: Offer[] = [];

this.offersService.getOffers().subscribe((response: Offer[]) => {

      for (let i in response) {
        this.offers[i] = Object.assign(new Offer(), response[i]);
      }
mjacob
  • 1
  • 6
  • Besides the fact that using `map` is cleaner than a for loop, it's basically the same answer as the accepted one. If you encountered another issue you should explain what it was and how your version solves this issue. – Carrm Oct 24 '22 at 09:29