Call variable from method in service


#1

Hi I’m trying to obtain some data from an injected service but I think in some point i’m doing it wrong.
Thanks in advance.
mi-servicio.js:

import {Injectable} from 'angular2/core';
import {Http} from 'angular2/http';
import 'rxjs/add/operator/map';
@Injectable()
export class MiServicio {
  static get parameters(){
    return [[Http]]
  }  
  constructor(http) {
    this.http = http;
    this.lasVets = null;
    // this.Vets();
  }
  loadVets(){
    this.http.get('./files/vets2.json')
    .map(res => res.json()).subscribe(
      data => {
        this.lasVets = data.vets;
      },
      err => {
        console.log("Error obtaining Vets :(");
      }
      );
  }
  Vets(){
    return this.lasVets;
  }
}

Now in some page i’m tryng to obtain what I return in Vets() method
map.js:

import {Page, NavController, Platform} from ‘ionic-angular’;
import {MiServicio} from ‘…/…/providers/mi-servicio/mi-servicio’;
@Page({
templateUrl: ‘build/pages/map/map.html’,
providers: [MiServicio]
})
export class MapPage {
static get parameters() {
return [[NavController],[Platform],[MiServicio]];
}
constructor(nav, platform, miServicio) {
this.nav = nav;
this.platform = platform;
this.initMap();
this.miServ = miServicio;
this.miServ.loadVets();
//this.miServ.Vets();
this.vets = null;
this.miServ.Vets().then((value) =>{
console.log(value);
});
// console.log(this.vets);
}
}


#2

This is confusing when we can’t see what types you are expecting instance members to be, but it looks like MiServicio.lasVets is an object of some sort, and not a Promise. However, you are calling then on it when it is returned from MiServicio.Vets(), which doesn’t make much sense.

It looks like you are still stuck in a synchronous mindset, where you think you can say (in the same thread of control):

this.miServ.loadVets(); 
// an asynchronous operation, but you're deluding yourself
// into believing that it's done now.
this.miServ.Vets()...
// you're relying on loadVets() being done, but it never will be
// so even if this call was typed properly, it will fail

I would recommend having loadVets return a Promise of whatever lasVets is supposed to be, and making the client code call then off of that. Do not have both loadVets() and Vets(). That is a broken design.


#3

Hi @rapropos thanks for your response. I tried to return as you mention:
return this.lasVets = data.vets; in LoadVets() method but I don’t know how to access from outside of the service.
Maybe I i got confused looking in a similar issue in the forum sorry.
So if let it like this:

loadVets(){
this.http.get(’./files/vets2.json’)
.map(res => res.json()).subscribe(
data => {
return this.lasVets = data.vets;
},
err => {
console.log(“Error obtaining Vets :(”);
}
);
}

How I properly access to the data?


#4

I think you would really benefit from more study of ReactiveX in general. I know it’s tempting to just ask for “please tell me how to get my data” and try to cargo cult your way through things, but it really isn’t sustainable.

Some heuristics:

  • if you are calling an asynchronous function that returns some sort of future, be it a Promise or an Observable, and you are doing so from a function that returns anything other than void, the very first word of that function should be return.
  • if you can use TypeScript, do so, and always declare return types, so anybody calling the function can see at a glance what it is supposed to return. i have no idea what you are intending these functions to return, so i don’t know if they’re being written improperly or called improperly.

I don’t know why lasVets is stored as an instance variable in MiServicio, so for simplicity I’m going to assume it can go away for the moment. I apologize for not being familiar with ES6 syntax (I despise JavaScript), so this is TypeScript and hopefully somebody can help you transcode it if needed. Perhaps something like this might work for you:

@Injectable()
export class MiServicio {
  constructor(private _http:Http) {
  }

  getVets(): Observable<Vets> {
    return this._http.get('./files/vets2.json')
    .map((rsp) => {
      return rsp.json();
    });
  }
}
@Page()
export class MapPage {
  vets:Vets;

  constructor(miServicio:MiServicio) {
    miServicio.getVets().subscribe((vets) => {
      this.vets = vets;
    }, (err) => {
      // deal with error
    });
  }
}

#5

Thanks @rapropos I find the solution looking for observables: here is the blog wich example helps me find the best solution: http://coenraets.org/blog/2016/02/angular2-ionic2-data-services-promises-observables/