I'm using ionic as a front end and Laravel as a back end.
This is the returned JSON data from an API URL, I want to access just the first element which is a.jpg without anything else, I tried using filenames.[0] but it's just displaying [ which means that it's calling the first character not the first element of the array.
Here's the JSON data:
[{"filenames":"[\"a.jpg\",\"b.jpg\",\"c.jpg\"]"}]
Here's my .ts file
import { ApiLandingRecipesService} from '../api-landing-recipes.service'
#Component({
selector: 'app-landing-page',
templateUrl: './landing-page.page.html',
styleUrls: ['./landing-page.page.scss'],
})
export class LandingPagePage implements OnInit {
datauser: any[];
constructor( public api: ApiLandingRecipesService) { }
ngOnInit() {
this.getDataUser();
}
async getDataUser() {
await this.api.getDataUser()
.subscribe(res => {
console.log(res);
this.datauser =res;
console.log(this.datauser);
}, err => {
console.log(err);
});
}
and Here's my service file:
import { Injectable } from '#angular/core';
import { HttpClient, HttpHeaders, HttpErrorResponse } from '#angular/common/http';
import { catchError, tap, map } from 'rxjs/operators';
import { Observable, throwError } from 'rxjs';
const httpOptions = {
headers: new HttpHeaders({'Content-Type': 'application/json'})
};
const apiUrl = "https://example.com/showimages";
#Injectable({
providedIn: 'root'
})
export class ApiLandingRecipesService {
constructor(private http: HttpClient) { }
private handleError(error: HttpErrorResponse) {
if (error.error instanceof ErrorEvent) {
console.error('An error occurred:', error.error.message);
} else {
console.error(
`Backend returned code ${error.status}, ` +
`body was: ${error.error}`);
}
return throwError('Something bad happened; please try again later.');
}
private extractData(res: Response) {
let body = res;
return body || [] ; }
getDataUser(): Observable<any> {
return this.http.get(apiUrl, httpOptions).pipe(
map(this.extractData),
catchError(this.handleError));
}
}
It's because filenames is indeed a string (a json string representation of the array) and not an array.
Try converting the string into an array first.
JSON.parse(filenames)[0]
The value of filenames here is a string and not an array, which is why you're getting [ when you try to access the first element.
You probably need to parse the value, here's an example (assuming datauser) is the JSON data you've shown us.
let filename = JSON.parse(datauser[0].filenames)[0]
Related
I am a beginner in angular and start to build my first app.My goal is to build a generic service that will be inherited from others service. I am following the structure of this link to my approach Generic HTTP Service .In read method i`m using Serializer class to convert the response json object to my typescript an it work. I got a map error. How can I solve it?
Service code:
import { Injectable } from '#angular/core';
import { Http, Headers } from '#angular/http';
import 'rxjs/add/operator/map';
import { HttpClient, HttpHeaders } from '#angular/common/http';
import { Resource } from '../models/resource.model';
import { Observable } from 'rxjs/Observable';
import { Serializer } from '../serializer/serializer';
import { AuthenticationService } from './authentication.service';
#Injectable()
export class SharedService<T extends Resource> {
constructor(
private httpClient: HttpClient,
private url: string,
private endpoint: string,
private authentication: AuthenticationService,
private serializer: Serializer
) { }
create(resource: T) {
let headers = new HttpHeaders();
headers = headers.set('Content-Type', 'application/json; charset=utf-8');
return this.httpClient.post(`${this.url}/${this.endpoint}`, JSON.stringify(resource), { headers: headers });
}
//PUT
update(item: T): Observable<T> {
return this.httpClient.put<T>(`${this.url}/${this.endpoint}`, JSON.stringify(item), { headers: this.addHeaders() })
.map(data => this.serializer.fromJson(data) as T);
}
//GET
read(id: number): Observable<T> {
return this.httpClient.get(`${this.url}/${this.endpoint}/${id}`, { headers: this.addHeaders() })
.map((data: any) => this.serializer.fromJson(data) as T);
}
//GET ALL
list(): Observable<T[]> {
return this.httpClient.get<T>(`${this.url}/${this.endpoint}` , {headers : this.addHeaders()})
.map((data: any) =>
this.convertData(data.items));
}
protected convertData(data: any): T[] {
return data.map(item => {this.serializer.fromJson(item)});
}
protected addHeaders() {
let token = ('Bearer ' + this.authentication.getToken()).valueOf();
let headers = new HttpHeaders();
headers = headers.set('Content-Type', 'application/json; charset=utf-8').set('Authorization', token);
return headers;
}
}
UserService:
import { Injectable } from '#angular/core';
import { SharedService } from './shared.service';
import { HttpClient, HttpHeaders } from '#angular/common/http';
import { User } from '../models/user/user.model';
import { AuthenticationService } from 'app/service/authentication.service';
import { UserSerializer } from '../serializer/user-serializer';
import { NgForm } from '#angular/forms';
#Injectable()
export class UserService extends SharedService<User>{
constructor(httpClient: HttpClient, authenticate: AuthenticationService) {
super(httpClient,
'http://localhost:8084/SuperCloud/webresources',
'user',
authenticate,
new UserSerializer()
);
}
UserSerializer:
import { User } from "../models/user/user.model";
import { Serializer } from "./serializer";
import { Resource } from "../models/resource.model";
export class UserSerializer extends Serializer {
fromJson(json: any): Resource {
const user = new User();
user.id = json.id;
user.name = json.name;
user.surname = json.surname;
user.email = json.email;
user.phoneNumber = json.phoneNumber;
user.password = json.password;
user.username = json.username;
user.active = json.active;
console.log('serializer');
console.log(user);
return user;
}
}
User model:
import { Resource } from "../resource.model";
export class User extends Resource{
username: string;
email: string;
name: string;
surname: string;
phoneNumber: string;
password?: string;
active : boolean;
}
UserService inherited inherited:
ngOnInit() {
this.userService.list().subscribe(
(data) => console.log(data)
);
}
Error:
core.es5.js:1020 ERROR TypeError: Cannot read property 'map' of
undefined
at UserService.SharedService.convertData (shared.service.ts:53)
at MapSubscriber.eval [as project] (shared.service.ts:48)
at MapSubscriber._next (map.js:79)
at MapSubscriber.Subscriber.next (Subscriber.js:95)
at MapSubscriber._next (map.js:85)
at MapSubscriber.Subscriber.next (Subscriber.js:95)
at FilterSubscriber._next (filter.js:90)
at FilterSubscriber.Subscriber.next (Subscriber.js:95)
at MergeMapSubscriber.notifyNext (mergeMap.js:151)
at InnerSubscriber._next (InnerSubscriber.js:25)
First of all, I assume the data that you passed into convertData function is not an array.
Only Array or Observable have map function in this case.
Also, chained function has been changed into pipeable operators in RxJS 6
https://github.com/ReactiveX/rxjs/blob/master/doc/pipeable-operators.md
Secondly, looking at the error message - I don't think the data value returned from the endpoint has value.
Third, data.map(item => {this.serializer.fromJson(item)}); - if the arrow function inside the map function is wrapped in curly bracket, you need to have return keyword.
in other word, data.map(item => {this.serializer.fromJson(item)}); should be data.map(item => this.serializer.fromJson(item)); or data.map(item => {return this.serializer.fromJson(item)});
Use subscribe instead of map to return the response.
return this.httpClient
.put<T>(`${this.url}/${this.endpoint}`, JSON.stringify(item), {
headers: this.addHeaders()
})
.subscribe(data => this.serializer.fromJson(data) as T);
BTW RXJs6 has changed the implementation of using observable map function
I want to get data from Riot API and display it in html view.
However, i can not "hold" this data in my variable. Console log show empty array.
I can see json data only in function scope.
I guess, i didn`t use observable function corretly, am i wrong?
Here is my component.
import { Component, OnInit } from '#angular/core';
import { FRIEND } from '../../services/_friends/mock-friends';
import { APIKEY } from '../../services/_lolapi/apikey';
import { Http, Response } from '#angular/http';
import { KeysPipe } from '../../pipes/key';
import { JsonPipe } from '#angular/common';
import 'rxjs/add/operator/map';
import { Observable } from 'rxjs/Observable';
#Component({
selector: 'app-friends',
templateUrl: './friends.component.html',
styleUrls: ['./friends.component.css']
})
export class FriendsComponent implements OnInit {
friends = FRIEND;
apikey = APIKEY;
nick: string[];
query: string;
private apiUrl =
'https://eun1.api.riotgames.com/lol/summoner/v3/summoners/by-name/';
data: Array<string> = [];
constructor(private http: Http) {
}
getFriendData(query) {
return this.http.get(query)
.map((res: Response) => res.json());
}
getContacts() {
this.getFriendData(this.query).subscribe(data => {
this.data = data;
console.log(this.data);
});
}
ngOnInit() {
for (let i of this.friends) {
this.query = `${this.apiUrl}${i.nick}${this.apikey}`;
this.getFriendData(this.query);
this.getContacts();
console.log(i.nick);
}
}
}
You don't need this.getFriendData(this.query) in ngOnInit as in the next line you call getContacts that wraps getFriendData.
Now, your API returns SummonerDTO - a complex object and you are trying to store it as an Array? That doesn't seem right.
Additionally, it think you want to store every result in an array, right?
In that case you should rather use:
this.data.push(data);
So I am trying to learn some basic Angular by creating an application that fetches and displays the current weather of a location using OpenWeather API.
This is what I have in my code currently:
app.component.ts:
import { Component } from '#angular/core';
import { WeatherService } from './weather.service';
#Component({
selector: 'app-root',
templateUrl: './app.component.html',
styleUrls: ['./app.component.css'],
providers: [WeatherService]
})
export class AppComponent {
title = 'Ng-Weather';
cityName: string;
weather: Weather;
constructor(private weather: WeatherService) { }
search() {
this.weather.getWeatherbyName(this.cityName)
.subscribe(res => this.weather = res);
console.log(this.weather);
}
}
weather.service.ts:
import { Injectable } from '#angular/core';
import { Http, Response, URLSearchParams } from '#angular/http';
import { Observable } from 'rxjs';
import { Weather } from './weather';
#Injectable()
export class WeatherService {
APIurl = "http://api.openweathermap.org/data/2.5/weather";
Appid = "xxx";
weather: Weather;
constructor(private http: Http) { }
getWeatherbyName(name: string): Observable<any> {
let myParams = new URLSearchParams();
myParams.append('appid', this.Appid);
myParams.append('q', name);
return this.http.get(this.APIurl , { search: myParams} )
.map(this.extractData)
.catch(this.handleError);
}
private extractData(res: Response) {
let body = res.json();
this.weather.city = body.name;
this.weather.description = body.weather[0].main;
this.weather.temp = body.main.temp;
console.log(this.weather);
}
private handleError(error: Response | any) {
console.error(error.message || error);
return Observable.throw(error.message || error);
}
}
weather.ts:
export class Weather {
city: String;
description: String;
temp: String;
}
So basically I am trying to map a JSON returned from OpenWeather API and get only some parts of the data and not the whole thing. The JSON returned is like following:
{
"coord":{
"lon":80.28,
"lat":13.09
},
"weather":[
{
"id":802,
"main":"Clouds",
"description":"scattered clouds",
"icon":"03n"
}
],
"base":"stations",
"main":{
"temp":303.15,
"pressure":1008,
"humidity":79,
"temp_min":303.15,
"temp_max":303.15
},
"visibility":6000,
"wind":{
"speed":3.1,
"deg":210
},
"clouds":{
"all":40
},
"dt":1504805400,
"sys":{
"type":1,
"id":7834,
"message":0.0017,
"country":"IN",
"sunrise":1504744074,
"sunset":1504788314
},
"id":1264527,
"name":"Chennai",
"cod":200
}
When the above code is executed, I get this error:
weather.service.ts:32 Cannot set property 'city' of undefined
Also how do I return an observable of type Weather and return that variable weather and catch it on the app.component.ts?
You are not creating an instance of the weather object before assigning its properties. You can do that explicitly like this:
this.weather = new Weather();
this.weather.city = body.name;
this.weather.description = body.weather[0].main;
this.weather.temp = body.main.temp;
console.log(this.weather);
OR
You can do something like this:
this.weather = {
city: body.name,
description: body.weather[0].main,
temp: body.main.temp
}
console.log(this.weather);
And to answer the second part of your question, you should be able to do this:
getWeatherbyName(name: string): Observable<Weather> {
// your other code
}
private extractData(res: Response) {
// your other code
return this.weather;
}
And to answer the third part of your question ... Observables are asynchronous. This means that they do not immediately return a value. Rather they provide for definition of a callback function that is executed when the data is returned. That means that the data is undefined until the data is returned and the callback function is executed.
So if you want to access the returned data in your code, you need to do in WITHIN the callback function. Like this:
search() {
this.weather.getWeatherbyName(this.cityName)
.subscribe(res => {
this.weather = res;
console.log(this.weather);
});
}
I am trying to get some JSON data by API that I have created, but it does not receive it. I have used the following Angular code:
getBook(id: string){
return this._http.get(this.url + 'books/' + id)
.map(res => {
console.log(res.json()); //It does not show anything
return res.json();
})
However the getBooks() method has no problems getting the data. There are no errors in the browser console.
This is the whole service code:
import { Injectable } from '#angular/core';
import { Http } from "#angular/http";
import 'rxjs/add/operator/map';
import { Observable } from "rxjs/Observable";
#Injectable()
export class LibrosService {
url: string = "http://localhost/API/public/index.php/api/";
constructor(private _http: Http) { }
getBooks(){
return this._http.get(this.url + 'books')
.map(res => res.json()); //it works
}
getBook(id: string){
return this._http.get(this.url + 'books/' + id)
.map(res => {
console.log(res.json()); //it does not work
return res.json();
})
}
Sorry for my English if it is not very good and thank you for your help.
In Service
getHeroes(): Observable<Hero[]> {
return this.http.get(this.heroesUrl)
.map(this.extractData)
.catch(this.handleError);
}
In Component
getHeroes() {
this.heroService.getHeroes()
.subscribe(
heroes => this.heroes = heroes,
error => this.errorMessage = <any>error);
}
Fortunately, a friend helped me find the solution because the most frustrating thing was console did not show any errors. And the problem was not in service, it was in component.
Here is my solution:
import { Component, OnInit } from '#angular/core';
import { ActivatedRoute } from "#angular/router";
import { BooksService } from "app/services/books.service";
import { Subscription } from "rxjs/Subscription";
#Component({
selector: 'app-book',
templateUrl: './book.component.html'
})
export class BookComponent implements OnInit {
public book: any =[];
private sub: Subscription;
public errorMessage: string;
constructor( private _activatedRoute: ActivatedRoute,
private _booksService: BooksService ) {}
ngOnInit() {
this.sub = this._activatedRoute.params
.subscribe(params => {
let id = +params['id'];
this.getBok(id);
});
}
getBok(id){
this._booksService.getBook(id)
.subscribe(book => {
this.book = book,
error => this.errorMessage = <any>error
});
}
}
Thanks all of you for your help.
I'm having an error in Ionic 2 "SyntaxError: Unexpected token < in JSON at position 3". My json format is correctly structured using spring boot.
Below is my spring boot code.
Appreciate your help.
#RequestMapping(value="/myview", method=RequestMethod.GET, produces = "application/json")
#ResponseBody
List<Client> myView( #ModelAttribute("client") Client client){
List<Client> data=(List<Client>) clientService.getAll();
return data;
}
import { Injectable } from '#angular/core';
import { Http } from '#angular/http';
import 'rxjs/add/operator/map';
#Injectable()
export class PeopleService {
people: any;
constructor(public http: Http) {}
load(){
if (this.people) {
return Promise.resolve(this.people);
}
return new Promise(resolve => {
this.http.get('http://localhost:8080/myview')
.map((res)=>res.json()).subscribe((data)=>{
console.log(data);
this.people=data;
resolve(this.people);
}, err=>{console.log(err)});
});
}// end load function
}
JSON from /myview
[{"id":1,"username":"donald#yahoo.com","policy":"V121293031","name":"Donald","mobile":"0504735260","email":"dcgatan#gmail.com","address":"Dafza Dubai","amount":800.98,"datetimestamp":1472861297000},{"id":3,"username":"dcgatan78#gmail.com","policyno":"V38998933","fname":"Donald","mobile":"0501234567","email":"dcgatan#gmail.com","address":"MetDubai","amount":334.34,"datetimestamp":1472862939000},{"id":4,"username":"dcgatan#yahoo.com","policyno":"V34342323","fname":"Snoopy","mobile":"0501234567","email":"dcgatan#yahoo.com","address":"Metlife Dafza Dubai","amount":883.43,"datetimestamp":1472916463000}]
My http://localhost:8080/myview is not working because when I tried the below code with Array value it works. How to call the http instead of putting static values in the Array?
import { Injectable } from '#angular/core';
import { Http } from '#angular/http';
import 'rxjs/add/operator/map';
#Injectable()
export class PeopleService {
people: Array<any> = [{"id":1,"username":"donald#yahoo.com","policyno":"V121293031","fname":"Donald","mobile":"0504735250","email":"dcgatan#gmail.com","address":"Dafza Dubai","amount":800.98,"datetimestamp":1472861297000},{"id":3,"username":"dcgatan78#gmail.com","policyno":"V38998933","fname":"Donald","mobile":"0501234567","email":"dcgatan#gmail.com","address":"MetLife Dubai","amount":334.34,"datetimestamp":1472862939000}];
constructor(private http: Http) {}
load(){
if (this.people) {
return Promise.resolve(this.people);
}
return new Promise(resolve => {
this.http.get('http://localhost:8080/myview')
.map((res)=>res.json())
.subscribe((data)=>{
this.setPeople(data);
resolve(this.people);
});
});
}// end load function
setPeople(data) {
if (data) {
for (let id of Object.keys(data)) {
let item = data[id];
item.id = id;
this.people.push(item);
}
}
}
}
Your call to /myview would be returning incorrect json. It must be having HTML elements. Performing res.json() extracts data from _body of the response, if it's valid. But in your case it is throwing an error.