How to extract data from SafeSubscriber? - json

I have to make an Angular application in which i get data from the back-end and display it on the front-end, but with some added hard-coded data.
My communication is between 2 files:
client.service.ts
import { Injectable } from '#angular/core';
import {HttpClient, HttpHeaders} from "#angular/common/http";
import {environment} from "../environments/environment";
import {catchError, map, Observable, of} from "rxjs";
const clientUrl = environment.apiUrl+'client';
#Injectable({providedIn: 'root'})
export class ClientService {
public optional: any;
constructor(private http: HttpClient) {}
getText(): Observable<any> {
console.log("it works!");
return this.http.get(clientUrl+"/getText").pipe(map(res => {
console.log(res);
this.optional = res.toString();
}));
}
}
and the second one:
client.component.ts
import { Component, OnInit } from '#angular/core';
import {ClientService} from "../client.service";
#Component({
selector: 'app-client',
templateUrl: './client.component.html',
styleUrls: ['./client.component.css']
})
export class ClientComponent implements OnInit {
public textResponse: any;
constructor(public service: ClientService) {}
ngOnInit(): void {}
getText() {
let text: any;
this.textResponse = this.service.getText().subscribe();
console.log(this.textResponse);
text = this.textResponse + "This text is added from code.";
console.log(text);
}
}
When i call "this.http.get(clientUrl+"/getText")" I get a SafeSubscriber object, from which i managed to get the data displayed in the console using the method ".subscribe(...)" with a "console.log()" inside of it. However, i did not find any method to extract the data out of this subscribe.
As the code above shows, i have tried to use pipe and map, but the local variable is returned as [Object object], and when i print it in the console i get either undefined, either nothing.
This is what my code currently displays:
it works! [client.service.ts:33]
SafeSubscriber {initialTeardown: undefined, closed: false, _parentage: null, _finalizers: Array(1), isStopped: false, …} [client.component.ts]
[object Object]This text is added from code. [client.component.ts]
{text: 'This text is read from a file.'} [client.service.ts]
I have also tried all the suggestions found in questions below:
angular 2 how to return data from subscribe
Angular observable retrieve data using subscribe
Does anyone know a method in which i could get the data out of the Subscribe?

You are missing the return keyword when mapping the response, looking at the console.log, you need the text property
getText(): Observable<any> {
console.log("it works!");
return this.http.get(clientUrl+"/getText").pipe(map(res => {
console.log(res);
this.optional = res.toString();
return res.text;
}));
}

Related

Angular2: json does not exist on type object

I am beginner. I am not able to solve this problem. i have read the other errors but still i am not able to understand.
While i am doing .map or .subscribe to the service it gives me error like Property 'json' does not exist on type object.
This is my: continents.component.ts
import { Component, OnInit } from '#angular/core';
import { DataContinentsService } from '../../services/dataContinents.service';
import 'rxjs/add/operator/map';
#Component({
selector: 'app-continents',
templateUrl: './continents.component.html',
styleUrls: ['./continents.component.css'],
providers: [DataContinentsService]
})
export class ContinentsComponent implements OnInit {
continent: any;
constructor(private dataContinentService: DataContinentsService) { }
public getContinentInfo() {
this.dataContinentService.getContinentDetail()
.map((response) => response.json())
.subscribe(res => this.continent = res.json()[0]);
}
ngOnInit() {}
}
This is my Service: DataContinentsService
import { Injectable } from '#angular/core';
import {HttpClientModule, HttpClient} from '#angular/common/http';
// import 'rxjs/add/operator/map';
#Injectable()
export class DataContinentsService {
constructor(private _http: HttpClient) {}
public getContinentDetail() {
const _url = 'http://restcountries.eu/rest/v2/name/india?fulltext=true';
return this._http.get(_url);
}
}
This is my Template: continents.component.html
<h1>Continents</h1>
<h3>Name: {{continent.name}}</h3>
<h3>Capital: {{continent.capital}}</h3>
<h3>Currency: {{continent.currencies[0].code}}</h3>
<button (click)="getContinentInfo()">get details</button>
I'm guessing that you've been reading some outdated documentation.
The old Http class used to return a response that did have a json() method.
The old Http class has been retired, and you are now properly using the HttpClient class. HttpClient's get() method returns an Observable of any - it maps the response's json to an object for you. Typically, you'd specify the type of the object, like so:
this.http.get<SomeObject>(url);
In lieu of that, you just get an Object.
In either case, there's no json() method on the returned object.
So, your service should do this:
public getContinentDetail(): Observable<Continent[]> {
const _url = 'http://restcountries.eu/rest/v2/name/india?fulltext=true';
return this._http.get<Continent[]>(_url);
}
you should subscribe something like this
this.dataContinentService.getContinentDetail().subscribe(continents: Continent[] =>
this.continent = continents[0]);
}

Angular 2 api data

I want to get data from Riot API and display it in html view.
However, i can not "hold" this data in my variable. Console log show empty array.
I can see json data only in function scope.
I guess, i didn`t use observable function corretly, am i wrong?
Here is my component.
import { Component, OnInit } from '#angular/core';
import { FRIEND } from '../../services/_friends/mock-friends';
import { APIKEY } from '../../services/_lolapi/apikey';
import { Http, Response } from '#angular/http';
import { KeysPipe } from '../../pipes/key';
import { JsonPipe } from '#angular/common';
import 'rxjs/add/operator/map';
import { Observable } from 'rxjs/Observable';
#Component({
selector: 'app-friends',
templateUrl: './friends.component.html',
styleUrls: ['./friends.component.css']
})
export class FriendsComponent implements OnInit {
friends = FRIEND;
apikey = APIKEY;
nick: string[];
query: string;
private apiUrl =
'https://eun1.api.riotgames.com/lol/summoner/v3/summoners/by-name/';
data: Array<string> = [];
constructor(private http: Http) {
}
getFriendData(query) {
return this.http.get(query)
.map((res: Response) => res.json());
}
getContacts() {
this.getFriendData(this.query).subscribe(data => {
this.data = data;
console.log(this.data);
});
}
ngOnInit() {
for (let i of this.friends) {
this.query = `${this.apiUrl}${i.nick}${this.apikey}`;
this.getFriendData(this.query);
this.getContacts();
console.log(i.nick);
}
}
}
You don't need this.getFriendData(this.query) in ngOnInit as in the next line you call getContacts that wraps getFriendData.
Now, your API returns SummonerDTO - a complex object and you are trying to store it as an Array? That doesn't seem right.
Additionally, it think you want to store every result in an array, right?
In that case you should rather use:
this.data.push(data);

Angular doesn't pass HTTP GET params properly

So I figuring out my way around Angular. Just started with a OpenWeather API based application using a simple GET method.
So here is my app.component.ts:
import { Component } from '#angular/core';
import { WeatherService } from './weather.service';
#Component({
selector: 'app-root',
templateUrl: './app.component.html',
styleUrls: ['./app.component.css'],
providers: [WeatherService]
})
export class AppComponent {
title = 'Ng-Weather';
cityName: string;
constructor(private weather: WeatherService) { }
search() {
this.weather.getWeatherbyName(this.cityName);
}
}
As you can guess, the cityName variable is two way binded. The search() function is invoked onclick of a button and the data is passed to the weatherservice. The contents of weather service is:
import { Injectable } from '#angular/core';
import { Http, Response, URLSearchParams } from '#angular/http';
import { Observable } from 'rxjs';
import { Weather } from './weather';
#Injectable()
export class WeatherService {
APIurl = "http://api.openweathermap.org/data/2.5/weather";
Appid = "xxx";
constructor(private Http: Http) { }
getWeatherbyName(name: string): Observable<any> {
let myParams = new URLSearchParams();
myParams.append('q', name);
myParams.append('appid', this.Appid);
// actual http request should look like this: http://api.openweathermap.org/data/2.5/weather?appid=xxx&q=Chennai
return this.Http.get(this.APIurl, { search: myParams})
.map(this.extractData)
.catch(this.handleError);
}
private extractData(res: Response) {
console.log(res.json());
let body = res.json();
return body.data;
}
private handleError(error: Response | any) {
console.error(error.message || error);
return Observable.throw(error.message || error);
}
}
But I get no error in my console or during the compile process. What is being done wrong? Also, how can I map the JSON I get to my class and give back that instance to the app.component?
Following is my class:
export class Weather {
city: String;
max_temp: String;
min_temp: String;
description: String;
}
And this is a sample JSON I receive:
{
"coord":{
"lon":80.28,
"lat":13.09
},
"weather":[
{
"id":803,
"main":"Clouds",
"description":"broken clouds",
"icon":"04n"
}
],
"base":"stations",
"main":{
"temp":304.15,
"pressure":1008,
"humidity":79,
"temp_min":304.15,
"temp_max":304.15
},
"visibility":6000,
"wind":{
"speed":3.1,
"deg":160
},
"clouds":{
"all":75
},
"dt":1504629000,
"sys":{
"type":1,
"id":7834,
"message":0.0029,
"country":"IN",
"sunrise":1504571272,
"sunset":1504615599
},
"id":1264527,
"name":"Chennai",
"cod":200
}
As you can see all I need is some data from the JSON and not the whole thing.
Your main problem here is that you are not subscribing to the observable that is being produced by your getWeatherbyName function. Observables returned by Http are cold:
Cold observables start running upon subscription, i.e., the observable sequence only starts pushing values to the observers when Subscribe is called. (…) This is different from hot observables such as mouse move events or stock tickers which are already producing values even before a subscription is active.
In order to subscribe to this observable, you can simply update your search function to the following:
search() {
this.weather.getWeatherbyName(this.cityName)
.subscribe();
}
This is by no means the complete solution to your problem - You will want to do something in the subscription, such as assign the information received to properties of your component so that they can be rendered in the UI.
You appear to have other issues in your linked project, but I suggest you ask separate questions on Stack Overflow if needed, or even better, your favorite search engine should be able to help.
Try passing a RequestOptions object to the http get instead:
import { RequestOptions } from '#angular/http';
getWeatherbyName(name: string): Observable<any> {
let myParams = new URLSearchParams();
myParams.append('q', name);
myParams.append('appid', this.Appid);
let options = new RequestOptions({ search: myParams}); //<----- NEW
// actual http request should look like this: http://api.openweathermap.org/data/2.5/weather?appid=xxx&q=Chennai
return this.Http.get(this.APIurl, options) //<<----- NEW
.map(this.extractData)
.catch(this.handleError);
}

Angular2 - cannot display json objects

my boss decided to implement Angular2 into our project. I'm preety new to this technology. I'm trying to display JSON from url, but the result is not as I expected. *ngFor doesn't display any data.
This is the code:
vehicle.service.ts
import { Injectable } from '#angular/core';
import { Http } from '#angular/http';
import 'rxjs/add/operator/map';
#Injectable()
export class VehicleService {
constructor(private http: Http){ }
getVehicle() {
return this.http.get('https://jsonplaceholder.typicode.com/posts')
.map(res => res.json());
}}
vehicle.component.ts
import { Component } from '#angular/core';
import { VehicleService } from './vehicle.service';
#Component({
moduleId: module.id,
selector: 'vehicle-json',
templateUrl: 'vehicle.html',
providers: [ VehicleService ]
})
export class VehicleComponent {
vehicle: Vehicle[];
constructor(private vehicleService: VehicleService){
this.vehicleService.getVehicle().subscribe(vehicle => {
/*console.log(vehicle);*/this.vehicle = vehicle;
});
}
}
interface Vehicle {
id: number;
title: string;
body: string;
}
vehicle.html
<div *ngFor="let vehicle of vehicles">
<h3>{{vehicle.title}}</h3>
<p>{{vehicle.body}}</p>
</div>
test 1-2-3
The output is: "test 1-2-3". I checked if the jsons will be displayed inside the console using: console.log(vehicle); - it worked, it returns Array of Objects.
What am I doing wrong? Any ideas how to fix my code?
You have an error:
this.vehicleService.getVehicle().subscribe(vehicle => {
this.vehicle = vehicle;
})
but in your html you refer to let vechicle of vehicles
You should add an "s" to your this.vehicle to your subscription like so:
this.vehicleService.getVehicle().subscribe(vehicle => {
this.vehicles = vehicle;
})
Edit: Just forgot to meantion to change the local variable vehicle: Vehicle[] to vechicles: Vehicle, but that you figured out that yourself! ;)

Angular 2 Form Serialization Into JSON Format

I am having a little bit of trouble creating my Angular 2 form and converting the submitted data into JSON format for the use of submitting it to my API. I am looking for something that works very similarly to this example:
$.fn.serializeObject = function()
http://jsfiddle.net/sxGtM/3/The only problem with this example is that the code is written in JQuery, whereas I'm trying to use strictly angular 2.
Any help would be greatly appreciated, I am still very new to angular.
You can use the getRawValue() function if you're using a FormGroup, to return an object that can then be serialized using JSON.stringify().
import { Component, OnInit } from '#angular/core';
import { FormGroup, FormBuilder } from '#angular/forms';
import { Http } from '#angular/http';
#Component({
selector: 'my-component',
templateUrl: 'my-component.component.html'
})
export class MyComponent implements OnInit {
form: FormGroup;
constructor(private fbuilder: FormBuilder,
private http: Http) { }
ngOnInit(){
this.form = this.fbuilder.group({
name: '',
description: ''
});
}
sendToAPI(){
let formObj = this.form.getRawValue(); // {name: '', description: ''}
let serializedForm = JSON.stringify(formObj);
this.http.post("www.domain.com/api", serializedForm)
.subscribe(
data => console.log("success!", data),
error => console.error("couldn't post because", error)
);
}
}
You can use JSON.stringify(form.value):
submit() {
let resource = JSON.stringify(this.form.value);
console.log('Add Button clicked: ' + resource);
this.service.create(resource)
.subscribe(response => console.log(response));
}
Result in Chrome DevTools:
You are looking for JSON.stringify(object) which will give you the JSON represantation of your javascript object.
You can then POST this using the built-in HTTP service to your server.