Object users in Observable Angular 8 - json

I created a service and I try call API method (HTTP GET) and I put my data in Observable, I don't understand why I don't see all data(object) from API GET.
angular-component.ts
public allUsers$: Observable<User[]>;
constructor(private usersService: UsersService) { }
ngOnInit() {
this.allUsers$ = this.getAllUsers();
console.log(this.allUsers$)
}
private getAllUsers(): Observable<User[]> {
return this.usersService.getUsers();
}
In console I have this message:
users.service.ts
public getUsers(): Observable<User[]> {
return this.apiService.get(this.type) as Observable<User[]>;
}
api.service.ts
public get(url: string): Observable<any> {
return this.http.get(environment.apiUrl + `/${url}`);
}
nodejs-route.js
app.get("/", async (req, res) => {
const getAllUsers = await User.find().populate("orders.order_id");
res.status(200).send(getAllUsers);
});

Always keep in mind that an Observable does nothing.
As the lead RxJS developer, Ben Lesh, once said:
Observables themselves are enert. They don't stream anything or do
anything. They are templates for streaming/actions/observations that
will be set up on a subscription.
And there are two basic ways to subscribe:
With an async pipe.
Using the subscribe method.
The async pipe in a template AUTOMATICALLY subscribes and unsubscribes for you.
So in your template, you'd have something like this:
<div class="card"
*ngIf="allUsers$ | async as users">
Then you will be able to access users in your template, such as in an *ngFor.
However, using an async pipe makes it a bit more difficult to access the data in your component code. So you can NOT just do this to see your data:
console.log(this.allUsers$)
All that will give you is information on the Observable, as you saw.
The other option is to subscribe in your component:
sub: Subscription
users: User[]
ngOnInit() {
this.sub = this.getAllUsers().subscribe(
users => {
this.users = users;
console.log(users);
);
}
The subscribe() method returns a Subscription that you can then use to manually unsubscribe.
You will then have an array of users User[], NOT an Observable<User[]> as your component property. Your template can then bind to this array.
The first technique (async pipe) is normally the recommended approach.

Related

Get past request without waiting for response (Angular 2 +)

I am looking for data in an API via Get request, I need the data inside my OnInit to use in composing other data. The problem is that the method is being called but it is as an async method (without await), it passes everywhere but when the return is obtained the excution of the main method has already been finished with no results. I tried the implementation of asynchronous methods but it did not solve.
service:
getObjects(): MyClass[] {
let objects = new Array<MyClass>();
this.obterTodos<MyClass>(this.uriApi)
.map(res => res.map(x => new MyClass(x.Description, x.Id)))
.subscribe(entities => {
objects = entities;
});
return objects ;
}
get request
public getObjects<TEntity>(url: string): Observable<TEntity[]> {
return this.httpService
.get(this.serviceUrl + url, this.options)
.map(res => res.json())
.catch(this.handleError);
}
component:
ngOnInit() {
this.myObjects= this.setorService.obterSetores();
console.log('this.myObjects is empty here');
}
so you'll want to subscribe to your observable in the component. This is typically done so the component can determine when the http request should be ran & so the component can wait for the http request to finish (and follow with some logic).
// subscribe to observable somewhere in your component (like ngOnInit)
this.setorService.obterSetores().subscribe(
res => {
this.myObjects = res;
},
err => {}
)
now the component knows when the http request finishes

Angular2: I can't get an external web api to load in the Tour of Heroes http services example [duplicate]

I have service which returns an observable which does an http request to my server and gets the data. I want to use this data but I always end up getting undefined. What's the problem?
Service:
#Injectable()
export class EventService {
constructor(private http: Http) { }
getEventList(): Observable<any>{
let headers = new Headers({ 'Content-Type': 'application/json' });
let options = new RequestOptions({ headers: headers });
return this.http.get("http://localhost:9999/events/get", options)
.map((res)=> res.json())
.catch((err)=> err)
}
}
Component:
#Component({...})
export class EventComponent {
myEvents: any;
constructor( private es: EventService ) { }
ngOnInit(){
this.es.getEventList()
.subscribe((response)=>{
this.myEvents = response;
});
console.log(this.myEvents); //This prints undefined!
}
}
I checked How do I return the response from an asynchronous call? post but couldn't find a solution
Reason:
The reason that it's undefined is that you are making an asynchronous operation. Meaning it'll take some time to complete the getEventList method (depending mostly on your network speed).
So lets look at the http call.
this.es.getEventList()
After you actually make ("fire") your http request with subscribe you will be waiting for the response. While waiting, javascript will execute the lines below this code and if it encounters synchronous assignments/operations it'll execute them immediately.
So after subscribing to the getEventList() and waiting for the response,
console.log(this.myEvents);
line will be executed immediately. And the value of it is undefined before the response arrives from the server (or to whatever that you have initialized it in the first place).
It is similar to doing:
ngOnInit(){
setTimeout(()=>{
this.myEvents = response;
}, 5000);
console.log(this.myEvents); //This prints undefined!
}
**Solution:**
>So how do we overcome this problem? We will use the callback function which is the `subscribe` method. Because when the data arrives from the server it'll be inside the `subscribe` with the response.
So changing the code to:
this.es.getEventList()
.subscribe((response)=>{
this.myEvents = response;
console.log(this.myEvents); //<-- not undefined anymore
});
will print the response.. after some time.
**What you should do:**
There might be lots of things to do with your response other than just logging it; you should do all these operations inside the callback (inside the subscribe function), when the data arrives.
Another thing to mention is that if you come from a Promise background, the then callback corresponds to subscribe with observables.
**What you shouldn't do:**
You shouldn't try to change an async operation to a sync operation (not that you can). One of the reasons that we have async operations is to not make the user wait for an operation to complete while they can do other things in that time period. Suppose that one of your async operations takes 3 minutes to complete, if we didn't have the async operations then the interface would freeze for 3 minutes.
Suggested Reading:
The original credit to this answer goes to: How do I return the response from an asynchronous call?
But with the angular2 release we were introduced to typescript and observables so this answer hopefully covers the basics of handling an asynchronous request with observables.
Making a http call in angular/javascript is asynchronous operation.
So when you make http call it will assign new thread to finish this call and start execution next line with another thread.
That is why you are getting undefined value.
so make below change to resolve this
this.es.getEventList()
.subscribe((response)=>{
this.myEvents = response;
console.log(this.myEvents); //<-this become synchronous now
});
You can use asyncPipe if you use myEvents only in template.
Here example with asyncPipe and Angular4 HttpClient example
Observables are lazy so you have to subscribe to get the value. You subscribed it properly in your code but simultaneously logged the output outside the 'subscribe' block. That's why it is 'undefined'.
ngOnInit() {
this.es.getEventList()
.subscribe((response) => {
this.myEvents = response;
});
console.log(this.myEvents); //Outside the subscribe block 'Undefined'
}
So if you log it inside the subscribe block then it will log response properly.
ngOnInit(){
this.es.getEventList()
.subscribe((response)=>{
this.myEvents = response;
console.log(this.myEvents); //Inside the subscribe block 'http response'
});
}
Here the problem is, you are initializing this.myEvents into subscribe() which is an asynchronous block while you are doing console.log() just out of subscribe() block.
So console.log() getting called before this.myEvents gets initialized.
Please move your console.log() code as well inside subscribe() and you are done.
ngOnInit(){
this.es.getEventList()
.subscribe((response)=>{
this.myEvents = response;
console.log(this.myEvents);
});
}
The result is undefined because angular process async .
you can trying as below:
async ngOnInit(){
const res = await this.es.getEventList();
console.log(JSON.stringify(res));
}
Also make sure that you map your response to a json output. Otherwise it will return plain text. You do it this like this:
getEventList(): Observable<any> {
let headers = new Headers({ 'Content-Type': 'application/json' });
let options = new RequestOptions({ headers: headers });
return this.http.get("http://localhost:9999/events/get", options)
.map((res)=>{ return res.json();}) <!-- add call to json here
.catch((err)=>{return err;})
}
Undefined because the value here is logged before any data from the service is set from that above subscribe service call. So you have to wait until the ajax call finishes and set the data from the response data.
getEventList(): Observable<any>{
let headers = new Headers({ 'Content-Type': 'application/json' });
let options = new RequestOptions({ headers: headers });
return this.http.get("http://localhost:9999/events/get", options)
.map((res)=> res.json())
.catch((err)=> err)
}
Here make the Console log inside the subscribe method that will make the log when the data is set in myEvents variable.
ngOnInit(){
this.es.getEventList()
.subscribe((response)=>{
this.myEvents = response;
// This prints the value from the response
console.log(this.myEvents)
});
}
To do this you have 2 options:
Suppose we have a service which is returning shipping details array :
getShippingPrices(): Observable<IShippingDetails[]> {
return this.http.get<IShippingDetails[]>('/assets/shipping.json');
}
1. Use Async pipe : Easy way when you just want to show the result in template
In the component class directly assign the observable to variable:
export class ShippingComponent implements OnInit {
shipOptions1 = this.cartService.getShippingPrices();
constructor(private cartService: CartService) {}
ngOnInit() {}
}
and then use async pipe in template :
<div *ngFor="let s of shipOptions1 |async">
<label>{{s.type}}</label>
</div>
Refer: Check the 4th point in this URL
https://angular.io/start/start-data#configuring-the-shippingcomponent-to-use-cartservice
2. Use Subscribe : When you want to manipulate it or want do some business logic on/from response
export class ShippingComponent implements OnInit {
shipOptions2: IShippingDetails[] = [];
constructor(private cartService: CartService) {}
ngOnInit() {
this.cartService.getShippingPrices().subscribe(response => {
this.shipOptions2 = response;
//console.log(this.myEvents);
//All other code using shipOptions2
});
}
}
You can simply try this method-
let headers = new Headers({'Accept': 'application/json'});
let options = new RequestOptions({headers: headers});
return this.http
.get(this.yourSearchUrlHere, options) // the URL which you have defined
.map((res) => {
res.json(); // using return res.json() will throw error
}
.catch(err) => {
console.error('error');
}

Variable return undefined value after assign it to value in Angular2 [duplicate]

I have service which returns an observable which does an http request to my server and gets the data. I want to use this data but I always end up getting undefined. What's the problem?
Service:
#Injectable()
export class EventService {
constructor(private http: Http) { }
getEventList(): Observable<any>{
let headers = new Headers({ 'Content-Type': 'application/json' });
let options = new RequestOptions({ headers: headers });
return this.http.get("http://localhost:9999/events/get", options)
.map((res)=> res.json())
.catch((err)=> err)
}
}
Component:
#Component({...})
export class EventComponent {
myEvents: any;
constructor( private es: EventService ) { }
ngOnInit(){
this.es.getEventList()
.subscribe((response)=>{
this.myEvents = response;
});
console.log(this.myEvents); //This prints undefined!
}
}
I checked How do I return the response from an asynchronous call? post but couldn't find a solution
Reason:
The reason that it's undefined is that you are making an asynchronous operation. Meaning it'll take some time to complete the getEventList method (depending mostly on your network speed).
So lets look at the http call.
this.es.getEventList()
After you actually make ("fire") your http request with subscribe you will be waiting for the response. While waiting, javascript will execute the lines below this code and if it encounters synchronous assignments/operations it'll execute them immediately.
So after subscribing to the getEventList() and waiting for the response,
console.log(this.myEvents);
line will be executed immediately. And the value of it is undefined before the response arrives from the server (or to whatever that you have initialized it in the first place).
It is similar to doing:
ngOnInit(){
setTimeout(()=>{
this.myEvents = response;
}, 5000);
console.log(this.myEvents); //This prints undefined!
}
**Solution:**
>So how do we overcome this problem? We will use the callback function which is the `subscribe` method. Because when the data arrives from the server it'll be inside the `subscribe` with the response.
So changing the code to:
this.es.getEventList()
.subscribe((response)=>{
this.myEvents = response;
console.log(this.myEvents); //<-- not undefined anymore
});
will print the response.. after some time.
**What you should do:**
There might be lots of things to do with your response other than just logging it; you should do all these operations inside the callback (inside the subscribe function), when the data arrives.
Another thing to mention is that if you come from a Promise background, the then callback corresponds to subscribe with observables.
**What you shouldn't do:**
You shouldn't try to change an async operation to a sync operation (not that you can). One of the reasons that we have async operations is to not make the user wait for an operation to complete while they can do other things in that time period. Suppose that one of your async operations takes 3 minutes to complete, if we didn't have the async operations then the interface would freeze for 3 minutes.
Suggested Reading:
The original credit to this answer goes to: How do I return the response from an asynchronous call?
But with the angular2 release we were introduced to typescript and observables so this answer hopefully covers the basics of handling an asynchronous request with observables.
Making a http call in angular/javascript is asynchronous operation.
So when you make http call it will assign new thread to finish this call and start execution next line with another thread.
That is why you are getting undefined value.
so make below change to resolve this
this.es.getEventList()
.subscribe((response)=>{
this.myEvents = response;
console.log(this.myEvents); //<-this become synchronous now
});
You can use asyncPipe if you use myEvents only in template.
Here example with asyncPipe and Angular4 HttpClient example
Observables are lazy so you have to subscribe to get the value. You subscribed it properly in your code but simultaneously logged the output outside the 'subscribe' block. That's why it is 'undefined'.
ngOnInit() {
this.es.getEventList()
.subscribe((response) => {
this.myEvents = response;
});
console.log(this.myEvents); //Outside the subscribe block 'Undefined'
}
So if you log it inside the subscribe block then it will log response properly.
ngOnInit(){
this.es.getEventList()
.subscribe((response)=>{
this.myEvents = response;
console.log(this.myEvents); //Inside the subscribe block 'http response'
});
}
Here the problem is, you are initializing this.myEvents into subscribe() which is an asynchronous block while you are doing console.log() just out of subscribe() block.
So console.log() getting called before this.myEvents gets initialized.
Please move your console.log() code as well inside subscribe() and you are done.
ngOnInit(){
this.es.getEventList()
.subscribe((response)=>{
this.myEvents = response;
console.log(this.myEvents);
});
}
The result is undefined because angular process async .
you can trying as below:
async ngOnInit(){
const res = await this.es.getEventList();
console.log(JSON.stringify(res));
}
Also make sure that you map your response to a json output. Otherwise it will return plain text. You do it this like this:
getEventList(): Observable<any> {
let headers = new Headers({ 'Content-Type': 'application/json' });
let options = new RequestOptions({ headers: headers });
return this.http.get("http://localhost:9999/events/get", options)
.map((res)=>{ return res.json();}) <!-- add call to json here
.catch((err)=>{return err;})
}
Undefined because the value here is logged before any data from the service is set from that above subscribe service call. So you have to wait until the ajax call finishes and set the data from the response data.
getEventList(): Observable<any>{
let headers = new Headers({ 'Content-Type': 'application/json' });
let options = new RequestOptions({ headers: headers });
return this.http.get("http://localhost:9999/events/get", options)
.map((res)=> res.json())
.catch((err)=> err)
}
Here make the Console log inside the subscribe method that will make the log when the data is set in myEvents variable.
ngOnInit(){
this.es.getEventList()
.subscribe((response)=>{
this.myEvents = response;
// This prints the value from the response
console.log(this.myEvents)
});
}
To do this you have 2 options:
Suppose we have a service which is returning shipping details array :
getShippingPrices(): Observable<IShippingDetails[]> {
return this.http.get<IShippingDetails[]>('/assets/shipping.json');
}
1. Use Async pipe : Easy way when you just want to show the result in template
In the component class directly assign the observable to variable:
export class ShippingComponent implements OnInit {
shipOptions1 = this.cartService.getShippingPrices();
constructor(private cartService: CartService) {}
ngOnInit() {}
}
and then use async pipe in template :
<div *ngFor="let s of shipOptions1 |async">
<label>{{s.type}}</label>
</div>
Refer: Check the 4th point in this URL
https://angular.io/start/start-data#configuring-the-shippingcomponent-to-use-cartservice
2. Use Subscribe : When you want to manipulate it or want do some business logic on/from response
export class ShippingComponent implements OnInit {
shipOptions2: IShippingDetails[] = [];
constructor(private cartService: CartService) {}
ngOnInit() {
this.cartService.getShippingPrices().subscribe(response => {
this.shipOptions2 = response;
//console.log(this.myEvents);
//All other code using shipOptions2
});
}
}
You can simply try this method-
let headers = new Headers({'Accept': 'application/json'});
let options = new RequestOptions({headers: headers});
return this.http
.get(this.yourSearchUrlHere, options) // the URL which you have defined
.map((res) => {
res.json(); // using return res.json() will throw error
}
.catch(err) => {
console.error('error');
}

How to map a JSON string into a TypeScript (JavaScript) object in AngularJS 2?

Consider this simple snippet of an AngularJS 2 application:
TestObject
export class TestObject {
id: number;
name: string;
}
TestService
[...]
export class TestService {
constructor(private http: Http) {}
test(): Observable<TestObject> {
return this.http
.get("http://www.example.com")
.map(this.save)
.catch(this.fail);
}
private save(response: Response) {
let testObject: TestObject = <TestObject> response.json();
return testObject || {};
}
private fail(error: any) {
return Observable.throw("error!");
}
}
AppComponent
[...]
export class AppComponent implements OnInit {
testObject: TestObject;
constructor(private testService: testService) {}
ngOnInit() {
this.testService.test().subscribe(
data => {
this.testObject = new TestObject();
console.log(this.testObject); // prints (empty) TestObject
this.testObject = data;
console.log(this.testObject); // prints object, not TestObject?
},
error => { }
);
}
}
Here my questions:
1) Why does my application print out (using Chrome Inspector) object and not TestObject as type?
2) The property testObject of class AppComponent should be of type TestObject. Why does my application not fail?
3) How can I achieve that I really get TestObject? What would be the best way to do it? Of course I could just manually fill up my TestObject, but I hoped there is some way of automatically mapping the json to my object.
Here is an answer that I wrote to a question which explained the handling of observables in angular2.
Angular 2 http post is returning 200 but no response is returned
Here you can see how I am handling the Response object as returned by the service. It is very important that you return your response object from the map function in service.
Similarly you can convert your response object to typescript type by casting your response object. The example can be:
this._loginService.login(this.username, this.password)
.subscribe(
(response) => {
//Here you can map the response to a type.
this.apiResult = <IUser>response.json();
//You cannot log your object here. Here you can only map.
},
(err) => {
//Here you can catch the error
},
() => {
//this is fired after the api requeest is completed.
//here you can log your object.
console.log(this.apiResult);
//result will only be shown here.
}
);
Here, it can be clearly seen that I am casting the response object to IUser type.
Another thing is while handling apiresponse in your component it is to be noted that the subscribe function has three arguments and if you will like to log your object, you must do it in the last function of subscribe.
Hope this helps!
your call must be like
ngOnInit() {
this.testService.test().subscribe(
(data) => {
this.testObject = new TestObject();
console.log(this.testObject); // prints (empty) TestObject
//only mapping
this.testObject = data;
},
error => { },
() => {
console.log(this.testObject);
}
);
}

Ionic2 and get Json

I am trying to use Ionic2 and I made a service to fetch a local stored Json.
import {Injectable} from 'angular2/core';
import {Http, Response} from 'angular2/http';
import {Observable} from 'rxjs/Rx';
import 'rxjs/add/operator/map';
#Injectable()
export class Page1Service {
public constructor(private _http: Http) {}
public GetItems() {
return this._http.get('/app/Ressources/Items.json').map((response: Response) => response.json().data);
}
public PrintJson():boolean {
var myresult;
this.GetItems().subscribe((result) => {
myresult = result;
console.log(result);
});
}
I also a made PrintJson() method that just print the json for test purpose.I got the error:
GET http://localhost:8100/app/Ressources/slides.json 404 (Not Found)
I don't get why. And I can't find an easy and uptodate tutorial. Or should I use fetch()?
First copy your json to the following dir(you can create the folder "data"):
[appname]/www/data/data.json
Type in the following command in your console:
ionic g provider JsonData
It should create a provider for you.Go to that page and enter the following in load() function:
load() {
if (this.data) {
// already loaded data
return Promise.resolve(this.data);
}
// don't have the data yet
return new Promise(resolve => {
// We're using Angular Http provider to request the data,
// then on the response it'll map the JSON data to a parsed JS object.
// Next we process the data and resolve the promise with the new data.
this.http.get('data/data.json').subscribe(res => {
// we've got back the raw data, now generate the core schedule data
// and save the data for later reference
this.data = res.json();
resolve(this.data);
console.log(this.data);
});
});
}
I usually create an Observable wrapped around the api-call like this:
public GetItems() {
return Observable.create(observer => {
this._http.get('/app/Ressources/Items.json').map(res =>res.json()).subscribe(data=>{
observer.next(data)
observer.complete();
});
});
}
Then I have to subscribe on that method in order to get the results and do something with it. (You could be to delegate the result to a list in the GUI)
GetItems().subscribe(data=>{
myResult = data;
});
EDIT: It might help to put this in the class as well
export class MyClass{
static get parameters(){
return [[Http]];
}
}
Just try to get the response.json() rather than response.json().data in GetItems() method
The issue is because of different paths of json files in local browser(computer) and device (android). Create data folder inside the src\assets folder. Move your json file into that.
When we run ionic serve, it will move that folder (with file) into www\assets folder. Then do following things:
Import Platform service of ionic2
import { Platform } from 'ionic-angular';
Inject Platform Service.
constructor(private http: Http, private platform: Platform ) { }
Use Platform Service.
public getItems() {
var url = 'assets/data/Items.json';
if (this.platform.is('cordova') && this.platform.is('android')) {
url = "/android_asset/www/" + url;
}
return this.http.get(url)
.map((res) => {
return res.json()
});
}