Can't print nested JSON data with Angular 6 - json

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.

Related

Using Angular11, how does my HomeComponent retrieve the data provided by the Subject in DataService?

In order to make the data accessible through out the app, I created a new service called the DataService where I want to store my data coming from the API in a Subject.
While I do get the data, I cen see the array of objects in a log from DataService, my array in HomeComponent that should get the data is undefined in the console:
browser inspector console output
I imagine I have some stupid errors in my code, I am a beginer. Could you help me ?
HomeComponent:
import {Component, OnInit, Output} from '#angular/core';
import {DataService} from '../../shared/services/data.service';
import {Subscription} from 'rxjs';
import {Article} from '../../shared/models/article';
#Component({
selector: 'app-home',
templateUrl: './home.component.html',
styleUrls: ['./home.component.scss']
})
export class HomeComponent implements OnInit {
#Output() articles?: Article[];
articleSubscription?: Subscription;
constructor(private dataService: DataService) { }
ngOnInit(): void {
this.dataService.emitArticlesSubject(this.dataService.loadArticles());
this.articleSubscription =
this.dataService.articlesSubject.subscribe(
(articles) => {
this.articles = articles;
}
);
console.log('HOME COMPONENT: ngOnInit: this.articles : ' + JSON.stringify(this.articles));
}
}
DataService:
import { Injectable } from '#angular/core';
import {BehaviorSubject, Subject} from 'rxjs';
import {ArticleService} from './article.service';
import {Article} from '../models/article';
#Injectable({
providedIn: 'root'
})
export class DataService {
articles?: Article[];
message = 'Aucun résultat ne correspond à votre recherche.';
articlesSubject = new Subject<Article[]>();
constructor(private articleService: ArticleService) { }
emitArticlesSubject(action: any): void {
this.articlesSubject.next(action);
}
/**
* Method to be served as a parameter
* to the 'emitArticlesSubject' method
* to load articles sorted by date.
*/
loadArticles(): any {
this.articleService.getAll().subscribe(
data => {
this.articles = data._embedded.articles;
console.log('DataService: loadArticles() : ' + JSON.stringify(this.articles));
},
error => {
console.log('ERROR: DataService not able to loadArticles !' );
}
);
}
/**
* Method to be served as a parameter
* to the 'emitArticlesSubject' method
* to load articles sorted by last activity.
*/
loadArticlesByActivity(): any {
this.articleService.getAllSortedByActivity().subscribe(
data => {
this.articles = data._embedded.articles;
},
error => {
console.log('ERROR: DataService not able to loadArticlesByActivity');
}
);
}
}
ArticleService:
import { Injectable } from '#angular/core';
import {HttpClient, HttpHeaders} from '#angular/common/http';
import {Observable} from 'rxjs';
import {Article} from '../models/article';
import {ResponseEntities} from '../../core/ResponseEntities';
const baseUrl = 'http://localhost:8080/articles';
const queryUrl = '?search=';
const dateUrl = '?sort=date,desc';
#Injectable({
providedIn: 'root'
})
export class ArticleService {
constructor(private http: HttpClient) { }
getAll(): Observable<ResponseEntities<Article[]>> {
return this.http.get<ResponseEntities<Article[]>>(`${baseUrl}${dateUrl}`);
}
getAllSortedByActivity(): Observable<ResponseEntities<Article[]>> {
return this.http.get<ResponseEntities<Article[]>>(`${baseUrl}/${dateUrl}`);
}
search(term: string): Observable<ResponseEntities<Article[]>> {
return this.http.get<ResponseEntities<Article[]>>(`${baseUrl}/${queryUrl}${term}`);
}
get(id: any): Observable<Article> {
return this.http.get<Article>(`${baseUrl}/${id}`);
}
create(data: any): Observable<any> {
return this.http.post(baseUrl, data);
}
update(id: any, data: any): Observable<any> {
return this.http.put(`${baseUrl}/${id}`, data);
}
delete(id: any): Observable<any> {
return this.http.delete(`${baseUrl}/${id}`);
}
deleteAll(): Observable<any> {
return this.http.delete(baseUrl);
}
findByTag(tag: any): Observable<Article[]> {
return this.http.get<Article[]>(`${baseUrl}?tag=${tag}`);
}
}
The problem could be related to subscription in data service.
this.dataService.emitArticlesSubject(this.dataService.loadArticles());
in this line emitArticlesSubject() called. but loadArticles() subscribed to underlaying service. emitArticlesSubject() only call loadArticles() and does not wait for its subscription to get complete. that causes articlss to be undefined. you should use promise in loadArticles() or change your service structures and call ArticleService directly in your HomeComponent.
In your HomeComponent you are console logging the contents of this.articles before the articles have actually been fetched. If you want to log the articles after they have been fetched, you can console log in the subscription instead:
this.articleSubscription =
this.dataService.articlesSubject.subscribe(
(articles) => {
this.articles = articles;
console.log('HOME COMPONENT: ngOnInit: this.articles : ' + JSON.stringify(this.articles));
}
);

ERROR TypeError: Failed to execute 'setRequestHeader' on 'XMLHttpRequest': Value is not a valid ByteString

I create an application using Node.js and Angular9.
It is used to allow anyone to establish a company on the site. When an employee comes to create a
company, he presses on the site "create a company" and a form appears to put the company name,
address and domain for it, and when he presses the "create" button, this problem appears.
Knowing that the backend is NodeJs.
And when I create a company using Postman I don't have any problems.
The problem is only on the part of the Angular.
when I execute the code from the Angular side, I have this problem:
ERROR TypeError: Failed to execute 'setRequestHeader' on 'XMLHttpRequest': Value is not a valid ByteString
and this Error:
ERROR CONTEXT
This is the Code:
Company.server.ts:
import { Injectable } from '#angular/core';
#Injectable()
export class CompanyService {
constructor() { }
}
Company.server.spec.ts:
import { TestBed, inject } from '#angular/core/testing';
import { CompanyService } from './company.service';
describe('CompanyService', () => {
beforeEach(() => {
TestBed.configureTestingModule({
providers: [CompanyService]
});
});
it('should be created', inject([CompanyService], (service: CompanyService) => {
expect(service).toBeTruthy();
}));
});
data.service.ts:
import { Injectable } from '#angular/core';
import { Observable } from 'rxjs';
import { HttpClient, HttpParams, HttpHeaders } from '#angular/common/http';
import { platformBrowserDynamicTesting } from '#angular/platform-browser-dynamic/testing';
import { BoundDirectivePropertyAst } from '#angular/compiler';
#Injectable()
export class DataService {
constructor(private httpClient: HttpClient) { }
create_company(body): Observable<any> {
var reqHeader = new HttpHeaders({
'Authorization': localStorage.getItem('token'),
'Content-Type': 'application/json'
});
return this.httpClient.post<any>
('http://localhost:3001/employee/company', body, { headers: reqHeader });
}
Company.component.ts:
import { Component, OnInit } from '#angular/core';
import { Router } from "#angular/router"
import { DataService } from '../../_services/data.service';
#Component({
selector: 'app-company',
templateUrl: './company.component.html',
styleUrls: ['./company.component.css']
})
export class CompanyComponent implements OnInit {
newCompany = {
company: {
name: '',
address: '',
domain: ''
}
}
public id: string;
public name: string;
public roles: any;
public email: string;
public token: string;
constructor(private dataService: DataService, private router: Router) { }
createCompany() {
console.log(JSON.stringify(this.newCompany));
console.log(localStorage.getItem('token'));
this.dataService.create_company(JSON.stringify(this.newCompany)).subscribe((data) => {
console.log(data);
})
}
logout() {
localStorage.clear();
this.router.navigate(['/register']);
}
ngOnInit() {
this.roles = localStorage.getItem('roles');
console.log(this.roles);
this.id = localStorage.getItem('id');
this.name = localStorage.getItem('name');
this.email = localStorage.getItem('email');
this.token = localStorage.getItem('token');
localStorage.setItem('id', "14ll06y4kbne6x6g");
localStorage.setItem('name', "Dalida");
localStorage.setItem('email', "dalida#gmail.com");
localStorage.setItem('roles', JSON.stringify([
{
roleId: 3,
targetId: '0',
employeeId: '14ll08o4kbm7apn9'
},
{
roleId: 2,
targetId: '4',
employeeId: '14ll08o4kbm7apn9'
}
]));
localStorage.setItem('token', 'eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpZCI6IjE0b…
I2MH0.wHUoGDYqZIsty1DqUxUtkuQReBUidS4mC0MAQi1bMtQ');
}
}
How can I solve this problem?

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?

Angular ignoring JSON fields on Object instantiation

I am trying to query the wagtail API that will return JSON in a very unfriendly format.
{
"id": 3,
"meta": {
"type": "home.HomePage",
"detail_url": "http://localhost:8000/api/v1/pages/3/"
},
"parent": null,
"title": "Homepage",
"body": "<h2>cool an h2 fgf</h2>",
"main_image": {
"id": 1,
"meta": {
"type": "wagtailimages.Image",
"detail_url": "http://localhost:8000/api/v1/images/1/"
}
},
"header_image": {
"id": 1,
"meta": {
"type": "wagtailimages.Image",
"detail_url": "http://localhost:8000/api/v1/images/1/"
}
},
"show_in_menus": true,
"full_url": "/media/images/Background-4.original.jpg"
}
All I really want from that is a class like this.
export class HomePage {
id: number;
title: string;
body: string;
full_url: string;
}
But whenever I get back from the data back from my service and try and log it, it is undefined.
Is there any way for me to ignore the fields I don't want from a JSON in typescript?
The service I am using is:
import { Injectable } from '#angular/core';
import {Http, Response} from '#angular/http';
import {Observable} from "rxjs";
import {HomePage} from "./HomePage";
#Injectable()
export class HomePageService {
constructor(private http: Http){
}
getHomePage(GUID: number): Observable<HomePage>{
return this.http
.get("http://localhost:8000/api/v1/pages/" + GUID + "/")
.map(this.extractData)
.catch(this.handleError);
}
private extractData(res: Response) {
let body = res.json();
return body.data || {}
}
private handleError (error: Response | any) {
// In a real world app, we might use a remote logging infrastructure
let errMsg: string;
if (error instanceof Response) {
const body = error.json() || '';
const err = body.error || JSON.stringify(body);
errMsg = `${error.status} - ${error.statusText || ''} ${err}`;
} else {
errMsg = error.message ? error.message : error.toString();
}
console.error(errMsg);
return Observable.throw(errMsg);
}
}
And the component:
import {Component, OnInit, OnDestroy} from '#angular/core';
import {HomePageService} from './home-page.service';
import {ActivatedRoute} from '#angular/router';
import {HomePage} from "./HomePage";
#Component({
selector: 'app-home-page',
templateUrl: './home-page.component.html',
styleUrls: ['./home-page.component.css'],
providers: [HomePageService]
})
export class HomePageComponent implements OnInit, OnDestroy{
id: number;
private sub: any;
public homePage: HomePage;
errorMessage: string;
constructor(private homePageService : HomePageService, private route: ActivatedRoute) {
}
ngOnInit() {
this.sub = this.route.params.subscribe(params => {
this.id = +params['id'];
});
this.homePageService.getHomePage(this.id)
.subscribe(
homePage => this.homePage = new HomePage(homePage),
error => this.errorMessage = <any>error,
() => console.log(this.homePage.full_url)
);
console.log(this.id);
}
ngOnDestroy() {
this.sub.unsubscribe();
}
}
homePage => this.homePage = new HomePage(homePage) - in your code I don't see a constructor defined for HomePage class. So when you pass the homePage object to it, nothing happens. Try this:
export class HomePage{
id: number;
title: string;
body: string;
full_url: string;
constructor(homePageObj: any)
{
if (homePageObj)
{
this.id = homePageObj.id;
this.title = homePageObj.title;
this.body = homePageObj.body;
this.full_url = homePageObj.full_url;
}
}
}

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 :)