Angular 4 - Mapping HTTP JSON Response - json

I am trying to setup a mean stack crud application. The routes and the functionality is setup and tested using postman. I am getting correct responses for all the routes. Now I am trying to add the view part where the routes are called internally by the Angular application. I am trying to setup a basic get route. Following is my component code:
import { Component, OnInit } from '#angular/core';
import { UserService } from '../user.service';
#Component({
selector: 'app-user',
templateUrl: './user.component.html',
styleUrls: ['./user.component.css']
})
export class UserComponent implements OnInit {
users: {};
constructor(private userService: UserService) { }
ngOnInit() {
this.getUsers();
}
getUsers() {
this.userService.getAllUsers().subscribe(data => this.users = data);
}
}
and the service contains the following code:
import { Injectable } from '#angular/core';
import { Http } from '#angular/http';
import 'rxjs/add/operator/map';
#Injectable()
export class UserService {
constructor(private http: Http) { }
getAllUsers() {
this.http.get('/api/users')
.map(res => res.json());
}
}
A sample response of the route using postman is as follows:
{
"status": true,
"err": null,
"data": [
{
"_id": "59d5db344c46e83a14b94616",
"name": "test"
},
{
"_id": "59d5db3c4c46e83a14b94617",
"name": "hello"
}
]
}
It always telling me the following error:
Property 'subscribe' does not exist on type 'void'.
What am I doing wrong? Can someone point me the standard way to do this?

Try this :
You forgot to return in your getAllUsers()
getAllUsers() {
return this.http.get('/api/users')
.map(res => res.json());
}

Related

Why would an angular service api not render to data bindings in the html?

I am still new to angular... But, this html renders as a blank page, nothing is shown in the browser. Console.log will log out the data to the console so I know it is visible. This also causes blank rows in a p-table or any other table that you might be using.
What am I doing wrong?
component.html
<div *ngFor="let item of myData">{{ item.id }}</div> <!-- should be: 1 2 3 -->
<div>{{ item[0].id }}</div> <!-- should be: 1 -->
component.ts
#Component({
selector: 'app-testing-table',
templateUrl: './testing-table.component.html',
styleUrls: ['./testing-table.component.css'],
})
export class TestingTableComponent implements OnInit {
myData: Posts[] = [];
constructor(
private postService: PostService,
) {}
ngOnInit(): void {
this.postService.get().subscribe((resp) => {
console.log('got all posts', resp);
this.myData = resp;
});
}
}
service.ts
import { HttpClient } from '#angular/common/http';
import { Injectable } from '#angular/core';
import { Observable } from 'rxjs/internal/Observable';
import { Posts } from '../models/posts';
#Injectable({
providedIn: 'root',
})
export class PostService {
public URL = 'https://something.com/typicode/demo/posts';
constructor(protected http: HttpClient) {}
public get(): Observable<Array<Posts>> {
return this.http.get<Array<Posts>>(`${this.URL}`);
}
}
model.ts
export class Posts {
id: number;
title: string;
}
Response Data from the API get() service.ts
[
{
"ID": 1,
"Title": "Post 1"
},
{
"ID": 2,
"Title": "Post 2"
},
{
"ID": 3,
"Title": "Post 3"
}
]
This took me a few good days of work with some help from a friend to find out angular is very strict with how it maps the JSON to the Model. The response data has to match 1:1 with the case or it wont work. The error is here:
Make the models match the response:
model.ts
export class Posts {
ID: number;
Title: string;
}
OR
Have the api service change what it returns as JSON, and have it return this instead:
Response Data from the API get() service.ts
[
{
"id": 1,
"title": "Post 1"
},
{
"id": 2,
"title": "Post 2"
},
{
"id": 3,
"title": "Post 3"
}
]

Angular 5 [object Object] error with json

I'm trying to load json data via httpclient using get in Angular 5. I'm using a service, interface, component and json file; I've followed a few tutorials already to try and get this to work as well as verified my json with jsonlint. From what I can see, everything should function, the json should be parsed and everything should be fine except I get 'error: [object Object]' in the console every time. I've tried various things to fix it, such as
data => this.jsonArticles = Object.values(data);
this.articles = data[0];
but I can't get my data into any other form.
article.service.ts
import { Injectable } from '#angular/core';
import { Article } from './article';
import { Observable } from 'rxjs/Observable';
import { HttpClient } from '#angular/common/http';
#Injectable()
export class ArticleService {
// Variables
private _jsonUrl: string = './assets/data.json';
// Constructors
constructor(private http: HttpClient) { }
// Methods
getArticles(): Observable<Article[]> {
return this.http.get<Article[]>(this._jsonUrl);
}
}
article.component.ts
import { Component, OnInit } from '#angular/core';
import { ArticleService } from '../article.service';
import { Article } from '../article';
#Component({
selector: 'app-article',
templateUrl: './article.component.html',
styleUrls: ['./article.component.scss']
})
export class ArticleComponent implements OnInit {
// Variables
public jsonArticles = [];
public errorMsg;
// Consturctors
constructor(private _articleService: ArticleService) { }
// Methods
ngOnInit(){
this._articleService.getArticles()
.subscribe(
data => this.jsonArticles = data,
error => this.errorMsg = error);
}
}
article.ts
export interface Article {
id: number;
author: string;
title: string;
content: string;
tags: string[];
categories: string[];
publishDate: string;
published: boolean;
}
data.json
[
{
"id": 3,
"author": "",
"title": "Fancy Meat",
"content": "Strip steak bresaola capicola tail cow chicken corned beef turkey.",
"tags": ["test", "lorum"],
"categories": ["blah"],
"publishDate": "2018-02-12T08:15:00.000-05:00",
"published": true
},
]
I truncated the json file for brevity, there are more entries in the file making my json object an array and there is no comma after the last entry in the json array.
I got this error because I forgot to import HttpClientModule into app.module.ts and declare it into imports
...
import { HttpClientModule } from '#angular/common/http';
#NgModule({
declarations: [
...
],
imports: [
BrowserModule,
FormsModule,
AppRouteModule,
HttpClientModule
],
providers: [],
bootstrap: [AppComponent]
})
export class AppModule { }

Pull data from a json file and display it with a button

I am trying to pull data from a json file and display it, but I am unable to proceed with the program because I lack experience in coding Angular.
Currently using Angular 4.3, which uses HttpClientModule.
app.component.ts
import { Component, OnInit } from '#angular/core';
import { HttpClient } from '#angular/common/http';
#Component({
selector: 'app-root',
templateUrl: './app.component.html',
styleUrls: ['./app.component.css']
})
export class AppComponent implements OnInit {
title = '?';
data;
constructor(private http: HttpClient) {
}
ngOnInit(): void {
this.http.get('/src/app/students.json')
}
chgTab1() {
this.title = "Changed Title";
}
chgTab2() {
//Want to display the items from json file
}
}
students.json
[
{"id": "3", "mame": "Dama"},
{"id": "1", "mame": "ASD"},
{"id": "2", "mame": "Chris"},
{"id": "4", "mame": "Sass"},
]
import { Component, OnInit } from '#angular/core';
import { Http,Headers } from '#angular/http';
import 'rxjs/add/operator/map';
#Component({
selector: 'app-root',
templateUrl: './app.component.html',
styleUrls: ['./app.component.css']
})
export class AppComponent implements OnInit {
title = '?';
data;
showData = false;
constructor(private http: Http) { }
ngOnInit(): void {
let headers = new Headers();
headers.append('Content-Type', 'application/json');
this.http.get('/assets/students.json', { headers: headers }).map(res => res.json()).subscribe(data => {
this.data = data;
})
}
chgTab1(){
this.title ="Changed Title";
}
chgTab2(){
//Want to display the items from json file
this.showData = !this.showData;
}
}
I have edited the whole thing. It will now work for you. Ensure you have the path to your student.json in the correct place.I moved it to the assets directory

Ionic 3 Cordova Native Storage storing modified data

I'm struggling to figure something out. Here's the relevant code.
types.json
{
"types": [
{"name": "Lateral Aids in Navigation", "enabled": false},
{"name": "Canal Structures", "enabled": true},
{"name": "Dockage", "enabled": true},
{"name": "Launch Points", "enabled": true},
{"name": "Landmarks", "enabled": true}
]
}
app.component.ts
import { Component } from '#angular/core';
import { Platform } from 'ionic-angular';
import { StatusBar } from '#ionic-native/status-bar';
import { SplashScreen } from '#ionic-native/splash-screen';
import { Http } from '#angular/http';
import { NativeStorage } from '#ionic-native/native-storage';
import { TabsPage } from '../pages/tabs/tabs';
import 'rxjs/add/operator/toPromise';
#Component({
templateUrl: 'app.html'
})
export class CanalGuide {
rootPage:any = TabsPage;
public types;
public places;
constructor(public http: Http, public platform: Platform, public
statusBar: StatusBar, public splashScreen: SplashScreen, public nativeStorage:
NativeStorage) {
platform.ready().then(() => {
// Okay, so the platform is ready and our plugins are available.
// Here you can do any higher level native things you might need.
statusBar.styleDefault();
this.readyTypes();
this.readyPlaces();
splashScreen.hide();
});
}
readyTypes() { return this.http.get('./assets/data/types.json').toPromise().then(
(types) => { this.nativeStorage.setItem('types', types) });
}
readyPlaces() { return this.http.get('./assets/data/canalwatertrail.json').toPromise().then(
(places) => { this.nativeStorage.setItem('places', places) });
}
}
settings.ts
import { Component } from '#angular/core';
import { Http } from '#angular/http';
import { NavController } from 'ionic-angular';
import { NativeStorage } from '#ionic-native/native-storage';
#Component({
selector: 'page-settings',
templateUrl: 'settings.html'
})
export class SettingsPage {
public toggles;
public types;
constructor(private http: Http, public navCtrl: NavController, public
nativeStorage: NativeStorage) {}
ionViewDidEnter() {
this.nativeStorage.getItem('types').then((data) => {
this.toggles = JSON.parse(data._body)
console.log(this.toggles);
});
}
// The relevant code
ionViewWillLeave() {
this.nativeStorage.setItem('types', this.toggles);
console.log(this.nativeStorage.getItem('types'));
}
}
settings.html
<ion-header>
<ion-navbar>
<ion-title>
Settings
</ion-title>
</ion-navbar>
</ion-header>
<ion-content>
<ion-list no-lines *ngIf="toggles">
<ion-list-header>Atlas Filters</ion-list-header>
<ion-item *ngFor="let type of toggles.types">
<ion-label>{{type.name}} - {{type.enabled}}</ion-label>
<ion-toggle [(ngModel)]="type.enabled"></ion-toggle>
</ion-item>
</ion-list>
My problem is this - The console.log() in ionViewWillLeave returns the following:
t {__zone_symbol__state: null, __zone_symbol__value: Array(0)}
__zone_symbol__state
:
true
__zone_symbol__value
:
{types: Array(5)}
__proto__
:
Object
Now in the ionicViewWillLeave function, how do I properly save the modifications to types.json back into Native Storage so it can be used again on a different page with nativeStorage.getItem? This seemingly simple function has been driving me crazy for a while now.
Please take a look at the documentation: https://ionicframework.com/docs/native/native-storage/
getItem and setItem return a promise, so you can't simply log it. You have to wait until the promise is resolved.
this.nativeStorage.setItem('types', {property: 'value', anotherProperty: 'anotherValue'})
.then(
() => console.log('Stored item!'),
error => console.error('Error storing item', error)
);
or
this.nativeStorage.getItem('types')
.then(
data => console.log(data),
error => console.error(error)
);

Make your pipe null-safe by returning null when null is passed as value

While using a pipe I was getting "NgFor only supports binding to Iterables such as Arrays." I received help from Guenter as can be seen from the comments, and then I ran into the issue with the keys pipe with the error "TypeError: Cannot convert undefined or null to object". Guenter then suggested to make the pipe null-safe by returning null when null is passed as value.
Here is my code on Plunker.
I am trying to print out the names of batch jobs in JSON format located here.
Here is the app.ts on Plunker:
import {Component, NgModule} from '#angular/core'
import {BrowserModule} from '#angular/platform-browser'
import { FormsModule } from '#angular/forms';
import { HttpModule, JsonpModule } from '#angular/http';
import { JobListComponent } from './job-list.component';
import { KeysPipe } from './keys.pipe';
import { JobService } from './job.service';
import { Job } from './job';
import { routing } from './app.routes';
#Component({
selector: 'my-app',
template: `
<div>
<header>
<div>
<!-- Title -->
<span>Jobs::</span>
<div>
{{jobs | json}}
<ul>
<li *ngFor="let job of jobs | keys">
<a>{{job.name}}</a>
</li>
</ul>
</div>
</div>
</header>
</div>
`,
})
export class App {
private json;
jobs: Observable<Job[]>;
constructor(private jobService: JobService) {}
ngOnInit() {
this.jobService.listJobs()
.subscribe(
jobs => {
this.jobs = jobs,
console.log(this.jobs)
console.log("AFTER")
});
}
}
#NgModule({
imports: [
BrowserModule,
FormsModule,
HttpModule
],
declarations: [ App,KeysPipe ],
providers: [JobService],
bootstrap: [ App ]
})
export class AppModule {}
I am using a pipe and I am trying to print the job name. It is modified as per Guenter's suggestion:
import {Component, Pipe, PipeTransform} from '#angular/core';
#Pipe({name: 'keys'})
export class KeysPipe implements PipeTransform {
transform(value: any, args?: any[]): any[] {
if(value == null) {
return;
}
let keys = Object.keys(value),
data = [];
keys.forEach(key => {
data.push(value[key]);
});
return data;
}
}
Here is the service:
import { Injectable } from '#angular/core';
//import { Jsonp, URLSearchParams } from '#angular/http';
import {Http, Response} from '#angular/http';
import { Job } from './job'
import 'rxjs/add/operator/map';
import {Observable} from "rxjs";
// Decorator to tell Angular that this class can be injected as a service to another class
#Injectable()
export class JobService {
// Class constructor with Jsonp injected
constructor(private http:Http) { }
// Base URI for Spring Batch Admin
private jobsUrl = 'https://api.myjson.com/bins/1n6lw';
// Get the list of jobs
listJobs() {
// RESTful service, list of jobs:
// http://localhost:8080/batch/jobs.json
const endPoint = 'jobs.json'
// Return response
return this.http.get(this.jobsUrl)
.map(res => <Job[]> res.json().jobs.registrations);
}
}
Here is the JSON I am trying to parse. I am trying to print the {{job.name}}:
{ "mecConsolidatorKickoutJob": { "name": "mecConsolidatorKickoutJob", "resource": "http://localhost:8080/batch/jobs/mecConsolidatorKickoutJob.json", "description": "No description", "executionCount": 460, "launchable": false, "incrementable": false },
"meceinJob": { "name": "meceinJob", "resource": "http://localhost:8080/batch/jobs/meceinJob.json", "description": "No description", "executionCount": 125, "launchable": false, "incrementable": false },
"mecmdwJob": { "name": "mecmdwJob", "resource": "http://localhost:8080/batch/jobs/mecmdwJob.json", "description": "No description", "executionCount": 701, "launchable": false, "incrementable": false },
"mecmdwvalidatingJob": { "name": "mecmdwvalidatingJob", "resource": "http://localhost:8080/batch/jobs/mecmdwvalidatingJob.json", "description": "No description", "executionCount": 1998, "launchable": false, "incrementable": false },
"mecssnJob": { "name": "mecssnJob", "resource": "http://localhost:8080/batch/jobs/mecssnJob.json", "description": "No description", "executionCount": 217, "launchable": false, "incrementable": false } }
Before all bindings are resolved or when inputs are used that are received from async calls or because just a value is never assigned to a property, parameters passed to a pipe can be null.
A pipe should not throw when null is passed. Just check
transform(value) {
if(!value) {
return;
}
// process values that are != null here
return result;
}
Plunker example