Angular 5 [object Object] error with json - 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 { }

Related

Angular 4 - Mapping HTTP JSON Response

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());
}

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

Ionic app getting data from url json

I don't know how to do this. I tried few examples from internet. What is the best solution?
import { Component } from '#angular/core';
#Component({
selector: 'page-hello-ionic',
templateUrl: 'hello-ionic.html'
})
export class HelloIonicPage {
constructor() {
}
}
to do this
Modify src/app/app.module.ts and import
import { HttpModule } from '#angular/http';
And Add to the Imports
#NgModule({
declarations: [
MyApp,
HomePage
],
imports: [
BrowserModule,
HttpModule,
IonicModule.forRoot(MyApp)
],
bootstrap: [IonicApp],
entryComponents: [
MyApp,
HomePage
],
providers: [
StatusBar,
SplashScreen,
{provide: ErrorHandler, useClass: IonicErrorHandler}
]
})
export class AppModule {}
After that you can use the HTTP Module from angular.
In your Page.ts
import the module and use it like this
import { Http } from '#angular/http';
constructor(public navCtrl: NavController, public http: Http) {
let url = "https://www.reddit.com/r/gifs/new/.json?limit=10";
this.http.get(url).map(res => res.json()).subscribe(data => {
console.log(data);
});
}
Additionally you can convert to returned JSON string to JSON Object
var jsonobject = JSON.parse(data)
And Alternatively you can use the IONIC NATIVE HTTP PLUGIN
Cheers :D
To do this just use the below code, no need to import any module
fetch('https://url.com').then(res => res.json())
.then(json => {
console.log(json)
});

Navigating & Passing Data Between Pages Ionic 2

I'm having some issues while navigating between pages with Ionic2.
I have a List of Data, that I got from a data.json
Here is the list
I want to get details:
Example - From "A"
The data that I have on my data/Example.Json
{
"title": "A",
"lat": 2.323733,
"lon": 64,546465
},
So as soon as I click on the Title, I want to get the title, lat and lon on a new page.
app.modules.ts
import { NgModule, ErrorHandler } from '#angular/core';
import { IonicApp, IonicModule, IonicErrorHandler } from 'ionic-angular';
import { MyApp } from './app.component';
import { HomePage } from '../pages/home/home';
import { MapPage } from '../pages/map/map';
import { ListPage } from '../pages/list/list';
import { DetailPage } from '../pages/detail/detail';
import { Locations } from '../providers/locations';
import { GoogleMaps } from '../providers/google-maps';
import { Connectivity } from '../providers/connectivity';
declare var google: any;
#NgModule({
declarations: [
MyApp,
HomePage,
MapPage,
ListPage,
DetailPage
],
imports: [
IonicModule.forRoot(MyApp)
],
bootstrap: [IonicApp],
entryComponents: [
MyApp,
HomePage,
MapPage,
ListPage,
DetailPage
],
providers: [{provide: ErrorHandler, useClass: IonicErrorHandler},Locations,GoogleMaps, Connectivity]
})
export class AppModule {}
import { NgModule, ErrorHandler } from '#angular/core';
import { IonicApp, IonicModule, IonicErrorHandler } from 'ionic-angular';
import { MyApp } from './app.component';
import { HomePage } from '../pages/home/home';
import { MapPage } from '../pages/map/map';
import { ListPage } from '../pages/list/list';
import { DetailPage } from '../pages/detail/detail';
import { Locations } from '../providers/locations';
import { GoogleMaps } from '../providers/google-maps';
import { Connectivity } from '../providers/connectivity';
declare var google: any;
#NgModule({
declarations: [
MyApp,
HomePage,
MapPage,
ListPage,
DetailPage
],
imports: [
IonicModule.forRoot(MyApp)
],
bootstrap: [IonicApp],
entryComponents: [
MyApp,
HomePage,
MapPage,
ListPage,
DetailPage
],
providers: [{provide: ErrorHandler, useClass: IonicErrorHandler},Locations,GoogleMaps, Connectivity]
})
export class AppModule {}
PageA.ts ( list of Data )
import { Component } from '#angular/core';
import { NavController } from 'ionic-angular';
import { Locations } from '../../providers/locations';
import { DetailPage } from '../detail/detail';
#Component({
selector: 'page-list',
templateUrl: 'list.html'
})
export class ListPage {
constructor(public navCtrl: NavController, public locations: Locations) {
}
ionViewDidLoad() {
console.log('Test Si marche');
}
viewLocation(event,location) {
this.navCtrl.push(DetailPage, {
"title":location.title,
"longitude":location.longitude
})
}
}
Page B ( where i want to get the detail as soon as i click on something on the list )
import { Component } from '#angular/core';
import { NavController } from 'ionic-angular';
import {NavParams} from "ionic-angular";
import { Locations} from '../../providers/locations';
import { ListPage } from '../list/list';
#Component({
selector: 'page-detail',
templateUrl: 'detail.html',
providers: [ Locations ],
entryComponents:[ ListPage ]
})
export class DetailPage {
title: string
latitude: string
navParams: NavParams
constructor(navParams: NavParams,public navCtrl: NavController) {
this.navParams = navParams
this.title = this.navParams.get('title');
this.latitude = this.navParams.get('latitude');
}
ionViewDidLoad(err) {
console.log(err);
}
goBack() {
this.navCtrl.pop();
}
}
listA.html
<ion-header>
<ion-navbar color="secondary">
<ion-title>List</ion-title>
</ion-navbar>
</ion-header>
<ion-content>
<ion-list no-lines>
<ion-item *ngFor="let location of locations.data">
<ion-item (click)="viewLocation($event, locations)">{{locations.title}}</ion-item>
<ion-avatar item-left>
<ion-icon name="pin"></ion-icon>
</ion-avatar>
<!--<img src="./src/pics/mus.png"/>-->
<h2>{{location.title}}</h2>
<p>{{location.distance*1.609}} Km</p>
</ion-item>
</ion-list>
</ion-content>
data.json
[
{ "title": "Cat", "longitude": "14,57" },
{ "title": "Bird", "longitude": "17.45" },
{ "title": "Spider", "longitude": "19,12" }
]
If you want to pass data from one page to another, you can either
1) Store your JSON data in SQL format via JSON.stringify(store) and JSON.parse(retrieving) method.
Meaning you stringify the data, before storing inside the SQL table and once retrieved from the next page, you do a JSON.parse to get back your JSON object.
You may want to read up on the following article on how to store data in SQL.
SQL Ionic 2
JSON Parse
JSON Stringify
Or either which, 2) you can make use of navController to "push" data from one page to another. One downside would be if your JSON data is huge, you will have to slowly iterate through.
A simple example would be:
this.navController.push(ThePageNameYouWannaGo, {
firstPassed: "firstData",
secondPassed: "secondData",
thirdPassed: "thirdData",
});
//On the next page (at your constructor),
Constructor(....,NavParams,.....){
this.first = navParams.get("firstPassed");
this.second= navParams.get("secondPassed");
this.third= navParams.get("thirdPassed");
//the value would be stored inside this.first, this.second respectively
For your case, I would recommend method 1 as I have no clue how big is your JSON file and to make your life easier in the future when your JSON file changes.

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