Async data handling in Angular - json

I'm trying to load a local JSON into my component, but I can't get the values from my service into my component. I can see the json data in the service but it is undefined in my component. Does anybody see what i'm doing wrong here ? Thanks.
Here is an SS of the console.log in both service and component
interfaces.json
{
"interfaces": {
"eth" : {"name" : "eth"},
"lte" : {"name" : "lte"},
"wlc" : {"name" : "wlc"},
"wlap" : {"name" : "wlap"}
}
}
interfaces.service.ts
import { Injectable } from '#angular/core';
import { Http } from '#angular/http';
#Injectable()
export class Interfaces {
constructor(public http: Http) {};
public getData() {
return this.http.get('/assets/interfaces.json')
.map((res) => {res.json(); console.log(res); });
};
}
interfaces.component.ts
import { Component, OnInit } from '#angular/core';
import { Interfaces } from './interfaces.service';
import { Observable } from 'rxjs/Rx';
#Component({
selector: 'interfaces',
providers: [
Interfaces
],
template: `
<ul *dropdownMenu class="dropdown-menu" role="menu">
<li *ngFor="let interface of interfaces | async" role="menuitem">
<a [routerLink]=" ['./interfaces/eth'] "routerLinkActive="active"
[routerLinkActiveOptions]= "{exact: true}" class="dropdown-item" href="#">
{{interface.name}}Main Ethernet
</a>
</li>
</ul>
`,
})
export class InterfacesComponent implements OnInit {
constructor(public interfaces: Interfaces) {}
public ngOnInit() {
this.interfaces.getData().subscribe((data) => { this.data = data; console.log(data); });
}
}

The reason that it's undefined is that you are not returning your response inside the map not that map is not working..
.map((res) => {console.log(res); return res.json(); }); // missing return here
or without brackets:
.map((res) => res.json());

I don't know what is wrong as I'm new to angular2, but this works for me.
interfaces.service.ts
import { Injectable } from '#angular/core';
import { Http } from '#angular/http';
#Injectable()
export class Interfaces {
constructor(public http: Http) {};
public getData() {
return this.http.get('/assets/interfaces.json');
}
}
interfaces.component.ts
import { Component, OnInit } from '#angular/core';
import { Interfaces } from './interfaces.service';
import { Observable } from 'rxjs/Rx';
export class InterfacesComponent implements OnInit {
constructor(public interfaces: Interfaces) {}
public ngOnInit() {
this.interfaces.getData().subscribe((data) => {
this.data = data;
console.log(data);
});
}
}

Related

Angular6 error: the data which I am getting from api is in the string format,below is the response image

hi want to show the data from my api to my frontend (Angular 6), but this error comes up: I am using HttpClient method from angular 6 I am new to angular
Angular6 error: the data which I am getting from api is in the string format, I need to convert it to object, below is the response image
this is model.ts
export class Incident {
public Title: string;
public status: string;
constructor(Title: string, status: string) {
this.status = status;
this.Title= Title;
}
}
this is component
import { Component, OnInit } from '#angular/core';
import { Router } from '#angular/router';
import { Incident } from '../../shared/incidents.model';
import { DataStorageService } from '../../shared/data-storage.service';
#Component({
selector: 'app-active-incident',
templateUrl: './active-incident.component.html',
styleUrls: ['./active-incident.component.css']
})
export class ActiveIncidentComponent implements OnInit {
incidents: Incident[];
constructor(private router: Router, private dataStorageService: DataStorageService) { }
ngOnInit() {
this.dataStorageService.getIncidents()
.subscribe(
(data: Incident[]) => this.incidents = data,
(err: any) => console.log(err),
() => console.log('All done getting incidents')
);
}
this is service
import { Injectable } from '#angular/core';
import { HttpClient } from '#angular/common/http';
import { Observable } from 'rxjs/Observable';
import { Incident } from './incidents.model';
#Injectable()
export class DataStorageService {
constructor(private http: HttpClient) {}
getIncidents(): Observable<Incident[]> {
console.log('Getting all incidents from server');
return this.http.get<Incident[]>
('api/url');
}
}
my json
{
"Events": ["{'title': 'some title', 'Incident_Status': 'status'}",
"{'title': 'some title', 'Incident_Status': 'status'}"]
}
html view
<div class="card" *ngFor="let incident of incidents">
<div class="card-header">
<span class="badge badge-danger"></span>{{incident.Title}}
<span class="badge badge-danger"></span>{{incident.Incident_Status}}
</div>
</div>
You are trying to iterate an object instead of an array. This happens because the list of events are inside the Events key, but you aren't accessing it to extract the list of events. Instead you are using the root of the response object.
Corrected code:
ngOnInit() {
this.dataStorageService.getIncidents()
.subscribe(
(data: Incident[]) => this.incidents = data.Events, // <--
(err: any) => console.log(err),
() => console.log('All done getting incidents')
);
}

Can't read url as JSON data

I have this JSON data and I'm getting it's output to a html file using angular. I use a service to get JSON data and a component to create the template. After using the template, I'm getting only id value and name value, but not url value.
JSON:
{
"A":1,
"B":[
{
"id":1,
"name":"One",
"url":"http://myapp/rootpath/first"
},
{
"id":2,
"name":"two",
"url":"http://myapp/rootpath/second"
}
]
}
I'm taking the JSON data to postArray variable in the component and pass it to the html file.
search.service.ts:
import { Injectable } from '#angular/core';
import {Http,Response} from "#angular/http";
import { Observable } from "rxjs";
import "rxjs/Rx";
import {JsoncallItem} from "./jsoncall-item";
#Injectable({
providedIn: 'root'
})
export class ApiService {
private postsURL ="http://myapp/items";
constructor(private http: Http ) {}
getPosts(): Observable<JsoncallItem[]>{
return this.http
.get(this.postsURL)
.map((response: Response)=> {
return <JsoncallItem[]>response.json();
})
.catch(this.handleError);
}
private handleError(error: Response) {
return Observable.throw(error.statusText);
}
}
search.component.ts
import { Component, OnInit } from '#angular/core';
import { ApiService } from "./../search.service";
import { JsoncallItem } from "./../jsoncall-item";
import { error } from 'util';
import { SearchtermPipe } from './../searchterm.pipe';
#Component({
selector: 'app-search',
templateUrl: './search.component.html',
styleUrls: ['./search.component.css']
})
export class SearchComponent implements OnInit {
title = 'app';
_postsArray: JsoncallItem[];
constructor(private apiSerivce: ApiService){}
getPosts(): void {
this.apiSerivce.getPosts().
subscribe(
resultArray => this._postsArray = resultArray
)
//error => console.log("Error :: " + error ))
}
ngOnInit(): void{
this.getPosts();
}
}
search.component.html:
<div class="container">
<ul>
<li *ngFor="let post of _postsArray | searchterm: value">
{{post.id}}, {{post.name}}, {{post.url}}
<hr>
</li>
</ul>
</div>
Output shows the id and name of each data, but not showing the url. What could be the wrong here?

Can't print nested JSON data with Angular 6

I'm learning to code and just ran into this issue with Angular 6 which I can't seem to solve. I was able to get JSON's data before but now that it's nested I don't know how to get it's data. This is what I've done so far
Service
import { Injectable } from '#angular/core';
import { Http, Response } from '#angular/http';
import { Observable } from 'rxjs';
import 'rxjs/add/operator/map';
import 'rxjs/add/operator/catch';
import 'rxjs/add/operator/toPromise';
#Injectable()
export class TestService {
url = "http://localhost:80/assets/data/test.json";
constructor(private http:Http) { }
getTestWithObservable(): Observable<any> {
return this.http.get(this.url)
.map(this.extractData)
.catch(this.handleErrorObservable);
}
private extractData(res: Response) {
let body = res.json();
return body;
}
private handleErrorObservable (error: Response | any) {
console.error(error.message || error);
return Observable.throw(error.message || error);
}
}
Component
import { Component, OnInit } from '#angular/core';
import { Observable } from 'rxjs';
import { TestService } from './test.service';
#Component({
selector: 'ngx-test',
styleUrls: ['./test.component.scss'],
templateUrl: './test.component.html',
})
export class TestComponent implements OnInit {
observableTest: Observable<any>
errorMessage: String;
constructor(private testService: TestService) { }
ngOnInit(): void {
this.testService.getTestWithObservable().subscribe(
res => {
let user = res[0]["users"];
let user_data = user["data"];
console.log(user_data["name"]);
}
);
}
}
JSON
[{
"id": 1,
"users": {
"user_id": 14,
"data": [{
"name": "James",
"age": 20
},
{
"name": "Damien",
"age": 25
}]
}
}]
HTML
<div *ngFor="let x of user_data; let i = index">
{{x.name}}
</div>
I'd appreciate if someone can point me out the solution or what I'm doing wrong.
You need to save the data in an instance property to access it. user_data is local to your function, you cannot access it in the template so you should use something like this :
export class TestComponent implements OnInit {
observableTest: Observable<any>
errorMessage: String;
user_data: any;
constructor(private testService: TestService) { }
ngOnInit(): void {
this.testService.getTestWithObservable().subscribe(
res => {
let user = res[0]['users'];
let user_data = user['data'];
console.log(user_data['name']);
this.user_data = user_data; // here
}
);
}
}
There is some problems with your code:
export class TestComponent implements OnInit {
observableTest: Observable<any>
errorMessage: String;
user_data: any;
constructor(private testService: TestService) {
}
ngOnInit(): void {
this.testService.getTestWithObservable().subscribe(
res => {
let user = res[0]["users"];
this.user_data = user["data"];
console.log(user_data["name"]);
}
);
}
}
In Angular >= 4, pipe methods is better to handle Observable
this.http.get(this.url)
.pipe(
filter(...),
map(...)
)
With HttpClient (Http is deprecated), the .json() is done for you. You don't need your extractData function.
You have to initialize your variable. And use "this" to refer to it.

Parent / Child component communication angular 2

I am failing to implement action button in child_1 component but the event handler is in sub child component child_2 as shown in the following code:
app.component.html (Parent Html)
<div style="text-align:center">
<h1>
Welcome to {{title}}!
</h1>
<app-navigation></app-navigation> <!-- Child1-->
</div>
app.component.html (Parent Component)
import { Component } from '#angular/core';
import { ProductService } from './productservice';
import {Product} from './product';
#Component({
selector: 'app-root',
templateUrl: './app.component.html',
styleUrls: ['./app.component.css'],
})
export class AppComponent {
title = 'MobileShirtShoeApp';
}
app.module.ts (Main Module)
import { BrowserModule } from '#angular/platform-browser';
import { NgModule } from '#angular/core';
import { HttpModule } from '#angular/http';
import { Product } from './product';
import { ProductService } from './productservice';
import { AppComponent } from './app.component';
import { NavigationComponent } from './navigation/navigation.component';
import { DataTemplateComponent } from './data-template/data-template.component';
#NgModule({
declarations: [AppComponent,NavigationComponent,DataTemplateComponent],
imports: [BrowserModule,HttpModule],
providers: [ProductService],
bootstrap: [AppComponent]
})
export class AppModule { }
navigation.component.html (Child 1 HTML)
<fieldset>
<legend>Navigate</legend>
<div>
<button (click)="loadMobiles()">Mobiles</button> <!--Child_1 Action-->
</div>
<app-data-template></app-data-template>
</fieldset>
navigation.component.ts (Child 1 Component.ts)
import { Component, OnInit } from '#angular/core';
import { ProductService } from '../productservice';
import {Product} from '../product';
import {DataTemplateComponent} from '../data-template/data-template.component';
#Component({
selector: 'app-navigation',
templateUrl: './navigation.component.html',
styleUrls: ['./navigation.component.css']
})
export class NavigationComponent implements OnInit {
error: string;
productArray: Product[];
constructor(private myService: ProductService){
this.myService = myService;
}
dataTemplateComponent: DataTemplateComponent = new DataTemplateComponent(this.myService);
ngOnInit() {
}
loadMobiles() {
return this.dataTemplateComponent.loadMobiles();
}
}
data-template.component.html (Child 2 HTML) (NOT DISPLAYING DATA)
<fieldset>
<legend>Requested Data</legend>
Welcome
<div>
<ul>
<li *ngFor="let product of productArray">
{{product.id}} {{product.name}} {{product.price}}
<img src="{{product.url}}">
</li>
</ul>
</div>
</fieldset>
data-template.component.ts (Child 2 Component) (Contains Product service calling code)
import { Component} from '#angular/core';
import {Product} from '../product';
import {ProductService} from '../productservice';
#Component({
selector: 'app-data-template',
templateUrl: './data-template.component.html',
styleUrls: ['./data-template.component.css']
})
export class DataTemplateComponent {
error: string;
productArray: Product[];
constructor(private productService: ProductService) {
this.productService = productService;
}
loadMobiles(){
let promise = this.productService.fetchMobiles();
promise.then(productArr => {
return this.productArray = productArr;
}).catch((err) => {
this.error = err;
});
}
}
ProductService.ts
import 'rxjs/add/operator/toPromise';
import {Http, HttpModule} from '#angular/http';
import {Injectable} from '#angular/core';
import {Product} from './product';
#Injectable()
export class ProductService{
http: Http;
constructor(http: Http){
this.http = http;
console.log(http);
}
fetchMobiles(): Promise<Product[]>{
let url = "https://raw.githubusercontent.com/xxxxx/Other/master/JsonData/MobileData.json";
return this.http.get(url).toPromise().then((response) => {
return response.json().mobiles as Product[];
}).catch(this.handleError);
}
private handleError(error: any): Promise<any> {
console.error('An error occurred', error);
return Promise.reject(error.message || error);
}
}
Sorry if the code bothers you. So basically i am failing to display service data in child_2.html when an action made in child_1.html.The service working fine and name is ProductService which uses Product.ts as an object to get the data in JSON format. Any kind of help is appreciated.
This doesn't work because the DataTemplateComponent you're instantiating in app-navigation isn't the same instance of DataTemplateComponent as the one on the page. It's a brand new one that you instantiated and that isn't bound to the page at all. What you're trying to achieve is component communication. Specifically, parent / child component communication. There are a number of ways to do this, the cleanest and most flexible / extensible way is with a shared service pattern. Basically, you declare a service with an observable in it that you inject into both services and one updates the observable while the other is subscribed to it, like this:
#Inject()
export class MyComponentCommunicationService {
private commSubject: Subject<any> = new Subject();
comm$: Observable<any> = this.commSubject.asObservable();
notify() {
this.commSubject.next();
}
}
Then provide this service, either at the app module or possibly at the parent component depending on needs then in app navigation:
constructor(private commService: MyComponentCommunicationService) {}
loadMobiles() {
this.commservice.notify();
}
and in data template:
constructor(private commService: MyComponentCommunicationService, private productService: ProductService) {}
ngOnInit() {
this.commSub = this.commService.comm$.subscribe(e => this.loadMobiles());
}
ngOnDestroy() { this.commSub.unsubscribe(); } // always clean subscriptions
This is probably a little unneccessary since you already have the product service there. You could probably just move the load mobiles logic into the product service and have that trigger an observable that the data template service is subscribed to, and have the nav component call the load mobile method on the product service, but this is just meant to illustrate the concept.
I'd probably do it like this:
#Inject()
export class ProductService {
private productSubject: Subject<Product[]> = new Subject<Product[]>();
products$: Observable<Product[]> = this.productSubject.asObservable();
loadMobiles() {
this.fetchMobiles().then(productArr => {
this.productSubject.next(productArr);
}).catch((err) => {
this.productSubject.error(err);
});
}
}
then nav component:
loadMobiles() {
this.myService.loadMobiles();
}
then data template:
ngOnInit() {
this.productSub = this.productService.products$.subscribe(
products => this.productArray = products,
err => this.error = err
);
}
ngOnDestroy() { this.productSub.unsubscribe(); } // always clean subscriptions

Angular 2 NFor loop not displaying

I don't get any errors to go off and the JSON is returned from the backend fine.
Question is, have I done anything wrong in the code below?
JSON
{
"Data": [{
"ProfileId": "121212",
"Name": "Charles",
"info": {
"rating": "0",
"plot": "Nothing happens at all."
}
}]
}
Home.Component.ts
import { Component, OnInit } from "#angular/core";
import { HomeService } from './home.service';
import { Profile } from './profile';
import 'rxjs/add/operator/map';
#Component({
moduleId: module.id,
selector: "home-page",
templateUrl: "home.component.html",
styleUrls: ["home.component.css"],
providers: [ HomeService ]
})
export class HomeComponent implements OnInit {
constructor(private service: HomeService) {}
Profiles: Profile[];
getProfile(): void {
this.service
.getData()
.then(profiles => this.Profiles = profiles);
}
ngOnInit(){
this.getProfile();
}
}
Home.service.ts
import {Injectable } from "#angular/core";
import {Headers, Http, Response} from '#angular/http';
import 'rxjs/add/operator/toPromise';
import { Profile } from './profile';
#Injectable()
export class HomeService {
private usersUrl = 'http://localhost:8888/';
private headers = new Headers({'Content-Type': 'application/json'});
constructor(private http: Http) {}
getData(): Promise<Profile[]> {
return this.http.get(this.usersUrl)
.toPromise()
.then(response => response.json().data as Profile[])
.catch(this.handleError);
//let err = new Error('Cannot get object of this type');
}
private handleError(error: any): Promise<any> {
console.error('An error occurred', error); // for demo purposes only
return Promise.reject(error.message || error);
}
}
home.component.html
<h2>HOME</h2>
<ul>
<li *ngFor="let prof of Profiles;">
{{prof.name}}
</li>
</ul>
Rendered as this in browser
{{prof.name}}
should be
{{prof.Name}}
Your picture gives a hint of the array being null with:
...ng-for-of: null
so besides the mention by Günther of that {{prof.name}} should be {{prof.Name}},
your JSON holds Data, (with capital letter), but in your get-request you are using data. This is actually case sensitive, so the following line
.then(response => response.json().data as Profile[])
should be:
.then(response => response.json().Data as Profile[])
that should populate your array correctly :)