get undefined for data assigned in service in angular 6 - javascript

I don't want to call the service in the .ts file. It will cause a lot of time. So I just want to assigned this as a global value that I can use, but I keep get undefined
Here is my service file
#Injectable({
providedIn: 'root'
})
export class DeService {
data:any;
constructor(private http: HttpClient){}
getData(id:any):Observable<any>{
this.http.get(Url.getDetails+"id="+id).pipe(first()).subscribe(res=>{
this.data = res;
console.log(this.data) //Here I got the data
}
return this.http.get(Url.getDetails+"id="+id)
}
}
the ts file
export class text implements OnInit{
constructor(public de:DeService){}
ngOnInIt(){
console.log(this.de.data); //here it returns undefind
}
}

You cannot access the observable like that, you need to call the method and subscribe to the method as follows,
getData(id:any):Observable<any>{
return this.http.get(Url.getDetails+"id="+id);
}
and in component,
ngOnInIt(){
this.de.getData(id).subscribe((data)=>{
console.log(data);
});
}

Since you are using Observable, and Observable works with async data, your data:any; is not initialized therefore it logs undefined.
This is happening
export class text implements OnInit{
constructor(public de:DeService){}
ngOnInIt(){
console.log(this.de.data); //here it returns undefind
}
}
Before this:
getData(id:any):Observable<any>{
this.http.get(Url.getDetails+"id="+id).pipe(first()).subscribe(res=>{
this.data = res;
console.log(this.data) //Here I got the data
}
return this.http.get(Url.getDetails+"id="+id)
}
To fix this you must set the data:any to some value or use #Sajeetharan solution ofcourse.

Related

Angular call to REST API not waiting for the data to arrived

I have the following code:
export class Whatever implements OnInitn{
prices;
ngOnInit(){
this.CoinPricesService.getPrices().subscribe(
pricesFromResponse => {
this.prices = pricesFromResponse;
console.log('this is what I get from the api: ', this.prices);
}
);
console.log('this is my prices class object', this.prices);
}
}
the output is this:
this is my prices class object undefined
api: this is what I get from the $, $ $
as you can see the first message is showing in second and the second is in the first place with an UNDEFINED,
obviously what is happening is that the code is not waiting for the response to come, is being sychronous, WHY ? isn't observable.Subscribe(response ==> this.myVar = response); meant to take care of that ?
I can't use the data in other places of my class because it's always undefined when the codes hits there, please help
My Service Looks like this:
#Injectable({
providedIn: 'root'
})
export class CoinPricesService {
private apiURl = 'https://api.forprices/blablabla';
constructor(private http: HttpClient) { }
getPrices(){
return this.http.get<any>(this.apiURl);
}
}
If you had a function that depended on price, then you could execute the functions within the subscribe.
something like this:
export class Whatever implements OnInitn{
prices;
ngOnInit(){
this.CoinPricesService.getPrices().subscribe(
pricesFromResponse => {
this.prices = pricesFromResponse;
console.log('this is what I get from the api: ', this.prices);
someFunction(pricesFromResponse)
}
);
}
someFunction(prices){//use price ...}
}

observable undefined in component - Angular

I have a service that connects with api
export class ConsolidadoApi {
constructor(private http: HttpClient) { }
getInvestiments(search?: any): Observable<any> {
return this.http.get<any>(`${environment.basePosicaoConsolidada}`);
}
}
Response this api:
https://demo5095413.mockable.io/consolidado
This one is responsible for the logic before reaching the component
#Injectable({
providedIn: 'root'
})
export class CoreService {
public test;
constructor(private api: ConsolidadoApi, private state: StateService) { }
public createMenu() {
this.api.getInvestiments()
.subscribe(response => {
console.log(response.carteiras[0])
this.products = response.carteiras[0]
return this.products;
})
}
In my component
export class MenuComponent implements OnInit {
constructor( private coreService : CoreService ) {}
ngOnInit(): void {
console.log(this.coreService.createMenu())
}
}
But when createMenu is called in menu.component.ts it comes undefined.
The raw response is an object. forEach works only on an array. If you are aiming for forEach in 'categorias', you should try
this.test.categorias.forEach()
When you return Observable<any>, that means the argument of the lambda you create when you do subscribe (which you named response) is type any. This doesn't necessary have the function forEach defined (unless the API returns an object with that prototype). That's generally why using any is not good practice; you can't have any expectations on what the object can contain. In fact, it's possible that it's not on object (it could be an array since any is not exclusively an object). If you do want to use forEach, you will want to make sure that response is type array. You can inspect the object's type before using it (e.g. using typeof) and make a judgement on what to call or even just check if the function you're trying to use is defined first, e.g. if (response.forEach !== undefined). You don't actually need to compare to undefined though, so if (response.forEach) suffices. In the examples, I used response, but you can use this.test since they are the same object after the first line in the lambda.
Based on the link you shared, the response is an object. You can log it to the console to confirm.
You can only call for each on an array, so for example, based on the response api, you can call forEach on the property ‘categorias’ and on that array’s children property ‘produtus’
Edit: this answer was based on the op original api and question
https://demo5095413.mockable.io/carteira-investimentos
public createMenu() {
return this.api.getInvestiments()
}
ngOnit() {
this.coreService.createMenu().subscribe(x => console.log(x.categorias))};
{
"codigo":1,
"categorias":[
{
"nome":"Referenciado",
"valorTotal":23000.0,
"codigo":"2",
"produtos":[
{
"nome":"CDB Fácil Bradesco",
"valor":2000.0,
"codigo":1,
"quantidade":0.0,
"porcentagem":0.5500,
"aplicacaoAdicional":500.0,
"codigoInvest":1,
"salaInvestimento":"CDB",
"permiteAplicar":true,
"permiteResgatar":true,
"movimentacaoAutomatica":false,
"ordemApresentacao":37,
"horarioAbertura":"08:30",
"horarioFechamento":"23:59",
"codigoGrupo":0,
"codigoMF":"001

angular load local file then make http calls to return observables

I am new to Angular, JS, and observables. I have a typescript class called DataService. I want it to load a list of URLs from a JSON formatted local file, and then have some way to call those URLs (to a handful of REST APIs) and return observables. The problem I am having is my code is not waiting for the config file to be loaded before the REST API functions get called.
I thought I could have the DataService constructor load the configuration file, and then have unique functions for each REST API call, but that isn't working
my code:
export class DataService {
configFile
constructor(private http: HttpClient) {
this.http.get('/assets/restApiUrlListConfig.json').subscribe(config => {
this.configFile = config;
});
}
getUrlFromConfigFile(name: string): string {
...
this returns the URL from the config file
...
}
getUrlAData(): Observable {
return this.http.get( getUrlFromConfigFile('A') )
}
}
My other components have code like this:
export class SomeComponent implements OnInit {
someComponentAData
constructor(private data: DataService) { }
ngOnInit() {
this.data.getUrlAData().subscribe(
data => {
this.someComponentAData = data
}
)
}
I am getting an error that the observable returned from the dataservice is undefined. Which I believe is because the constructor hasn't finished loading the config file, which I think is why the function getUrlAData isn't returning anything.
I feel like I'm not correctly handling these async calls, but I'm at a loss for how to tell my code to :
create the data service object
load the data file before anything else can be done
allow the other functions to be called asyncronously AFTER the config file is loaded
Angular CLI: 6.2.3
Node: 8.12.0
OS: win32 x64
Angular: 6.1.8
Edit 1: attempting to implement suggested solution
My DataService
configFile
configObservable: Observable<any>;
someSubscribeObj
constructor(private http: HttpClient) {
this.someSubscribeObj = this.http.get('/assets/restApiUrlListConfig.json').subscribe(config => {
this.someSubscribeObj = undefined;
this.configFile = config;
});
}
getObsFromConfigFile(name: string): Observable<any> {
//...
if (this.configFile != undefined) {
console.log('this.restApiUrlListConfig[name]',this.configFile[name])
return of(this.configFile[name])
}
else
return of(this.someSubscribeObj.pipe(map(c => c[name])))
//this.configObservable
//...
}
getUrlAData(): Observable<any> {
return this.getObsFromConfigFile('A').pipe(mergeMap(url => this.http.get(url)))
}
My other component:
constructor( private data: DataService ) { }
ngOnInit() {
//this.data.loggedIn.pipe((p) => p);
this.data.getUrlAData().subscribe(
data => {
this.urlAData = data
}
)
}
I was unable to store the "subscribe" into the observable, so I created a generic Any type varable, but at runtime I get a problem with the pipe command:
TypeError: this.someSubscribeObj.pipe is not a function
at DataService.push../src/app/services/data.service.ts.DataService.getObsFromConfigFile
(data.service.ts:67)
at DataService.push../src/app/services/data.service.ts.DataService.getUrlAData
(data.service.ts:74)
Edit 2: the unfortunate workaround
I am currently using two nested subscriptions to get the job done basically
http.get(config_file_url).subscribe(
config => {
http.get( config['A'] ).subscribe( adata => { do things };
http.get config['B'].subscribe( bdata => {do things };
}
)
I feel like I should be able to use a mergeMap of some sort, but I couldn't get them to work as I thought they would.
You need to wait on that async call, I would use a flatmap to get the value out of an observable.
export class DataService {
configFile
configObservable: Observable<any>;
constructor(private http: HttpClient) {
this.configObservable = this.http.get('/assets/restApiUrlListConfig.json').pipe(
map(config => {
this.configObservable = undefined;
this.configFile = config;
return configFile;
})
);
}
getUrlFromConfigFile(name: string): Observable<string> {
...
return of(configFile[name]) if configFile is set else return configObservable.pipe(map(c => c[name]));
...
}
getUrlAData(): Observable<string> {
return this.getUrlFromConfigFile('A').pipe(map(url => this.http.get(url)))
}
}
Basically you want to store the observable and keep using it till it completes, after it completes you can just wrap the config in an observable. The reason for wrapping it is to make the interface consistent, otherwise you have to have an if before every get.

Why we need to inject service through constructor in angular2?

I'm learning Angular 2. And got confused over constructor.
Consider the below code :
import { Component, OnInit } from '#angular/core';
import { FormGroup,FormsModule,FormControl } from '#angular/forms';
import { WeatherService } from '../weather.service';
import { WeatherItem } from '../weather-item';
#Component({
selector: 'app-weather-search',
templateUrl: './weather-search.component.html',
styleUrls: ['../../assets/app.css'],
//providers: [WeatherService]
})
export class WeatherSearchComponent implements OnInit {
constructor(private _weatherService : WeatherService) { }
onSubmit(form : FormGroup){
//alert(form.value.location);
this._weatherService.searchWeatherData(form.value.location)
.subscribe(
data => {
const weatherItem = new WeatherItem(data.data.request["0"].query,data.data.weather["0"].maxtempC,data.data.weather["0"].maxtempC);
this._weatherService.addWeatherItems(weatherItem);
console.log(form);
})
}
ngOnInit() {
}
}
Here we are injecting 'WeatherService' in constructor. Can't we do the same outside constructor ? What constructor is doing here actually? Do we really need it here?
The constructor itself is not doing actual work.
Angular creates a new WeatherSearchComponent executing
new WeatherSearchComponent(weatherService);
and this causes the constructor in WeatherSearchComponent to receive the weatherService value.
The constructor
constructor(private _weatherService : WeatherService)
causes an instance field _weatherService to be created and initialized with the value passed from DI.
The constructor is the only place where it is easy to know when the injected service is available and when not.
If the service would passed to a field, setter or method, code in the constructor could not access it because the constructor is executed before outside code has a change to set a field or call a method.
Also for code outside the constructor it is not safe to assume the service is available because this code could be called from the constructor before a field could be set from the outside.
For dependency injection passing dependencies to the constructor is the only way to avoid a lot of complexity.
Dependency Injection in constructor is always better option and while the component is getting created it will get the weatherService as a parameter. To make it clear, below is the transpiled code for your snippet.
var WeatherSearchComponent = (function () {
function WeatherSearchComponent(_weatherService) {
this._weatherService = _weatherService;
}
WeatherSearchComponent.prototype.onSubmit = function (form) {
var _this = this;
//alert(form.value.location);
this._weatherService.searchWeatherData(form.value.location)
.subscribe(function (data) {
var weatherItem = new weather_item_1.WeatherItem(data.data.request["0"].query, data.data.weather["0"].maxtempC, data.data.weather["0"].maxtempC);
_this._weatherService.addWeatherItems(weatherItem);
console.log(form);
});
};
WeatherSearchComponent.prototype.ngOnInit = function () {
};
WeatherSearchComponent = __decorate([
core_1.Component({
selector: 'app-weather-search',
templateUrl: './weather-search.component.html',
styleUrls: ['../../assets/app.css'],
})
], WeatherSearchComponent);
return WeatherSearchComponent;
}());
exports.WeatherSearchComponent = WeatherSearchComponent;
As you can see in turn the javascript code has weatherService Instance being passed on to the function weatherSearchComponent.

Angular HttpClient get, wrong this object

in my Angular App i make a simple call to a node.js server. the HttpClient "get"
function returns the right answer. This answer I want to store in a variable of my component "interfaces". But in the "subscribe" function of the get request my "this" pointer doesn't point to my component. Instead it tells me that it is of type "SafeSubscriber". Any call to my member "interfaces" lead to the following error:
TypeError: Cannot read property 'interfaces' of undefined
export class SettingsComponent implements OnInit {
public interfaces : string[];
constructor(private http: HttpClient) {
this.interfaces = [];
this.interfaces.push("huhu");
}
ngOnInit() : void {
this.http.get('http://localhost:3000/settings/interfaces').subscribe((data) => {
// Read the result field from the JSON response.
console.log(data);
this.interfaces.push("xxx");
Object.keys(data).forEach(function(k) {
console.log(k);
this.interfaces.push("xxx");
});
}),
err => {
console.log("error " + err);
};
}
}
As you can see I also tried to enter some values manually into the array just to make sure, that not the server response is causing the problem.
Any help is appreciated.
I used this code as a blueprint which is from:
https://angular.io/guide/http
#Component(...)
export class MyComponent implements OnInit {
results: string[];
// Inject HttpClient into your component or service.
constructor(private http: HttpClient) {}
ngOnInit(): void {
// Make the HTTP request:
this.http.get('/api/items').subscribe(data => {
// Read the result field from the JSON response.
this.results = data['results'];
});
}
}
You're losing reference to the correct this in this statement:
Object.keys(data).forEach(function(k) {..})
Inside the function block code this refers to the calling context , which is the subscribe method itself, that's why interfaces is undefined, since it's not a property of the subscribe method.
You can change the function for a lambda en it should be fine:
Object.keys(data).forEach((k) => {..})

Categories