I'm trying to read a json object that is returned from a JSONP API call on Angular 4, but I keep getting "undefined" in the console when I try to print it.
This is my SearchService.ts file:
import {Injectable} from '#angular/core';
import {Jsonp} from '#angular/http';
import 'rxjs/add/operator/map';
#Injectable()
export class SearchService {
apiRoot = 'this/is/my/api';
results: any;
loading: boolean;
constructor(private jsonp: Jsonp) {
this.loading = false;
}
search(term: string) {
const apiUrl = `${this.apiRoot}?search=${term}&rows=10&callback=JSONP_CALLBACK`;
return this.jsonp.request(apiUrl).map(results => { this.results = results.json().data
});
}
}
And this is the search.component.ts file that I'm using to carry out the search:
import {Component, OnInit} from '#angular/core';
import 'rxjs/add/operator/toPromise';
import {SearchService} from '../../services/SearchService';
#Component({
selector: 'app-search',
templateUrl: './search.component.html',
styleUrls: ['./search.component.css']
})
export class SearchComponent implements OnInit {
loading = false;
public result;
constructor(private uniDirectory: SearchService) {
}
doSearch(term: string) {
this.loading = true;
this.uniDirectory.search(term).subscribe(results => this.result = results);
this.loading = false;
console.log('Result: ' + this.result);
}
ngOnInit() {
}
}
If I try and print the result in the SearchService (i.e. console.log(results.json());), the json object is printed out. However, if I try to print out the same in the doSearch() method, then it prints undefined. Any suggestions are appreciated.
Looks like you missing a return in your sevice,s map function,
try this one
search(term: string) {
const apiUrl = `${this.apiRoot}?search=${term}&rows=10&callback=JSONP_CALLBACK`;
return this.jsonp.request(apiUrl)
.map(results => {
this.results = results.json().data;//you might not need this one
return results.json(); //add this one
});
}
I managed to fix it (someone initially posted this as an answer and removed it before I could accept it):
this.uniDirectory.search(term).subscribe((results) => {
this.result = results;
console.log(this.result);
});
Related
There is a lot of documentation and examples of firestore collections getting realtime updates. However, there is very little for those who wish to have a single document have real time updates. I want to have a single document (an item), on a page where only the item will be viewed and manipulated and any changes to document, will have realtime updating.
Here is my component that wants to do stuff with the item:
import { Component, OnInit } from '#angular/core';
import { ItemsService } from '../shared/items.service';
import { ActivatedRoute, Router } from '#angular/router';
#Component({
selector: 'app-view-item',
templateUrl: './view-item.component.html',
styleUrls: ['./view-item.component.css']
})
export class ViewItem implements OnInit {
item;
private sub: any;
constructor(
// Service used for Firebase calls
private itemsService: ItemsService,
private route: ActivatedRoute,
private router: Router
) {}
ngOnInit() {
// Item retrieved from */item/:id url
this.sub = this.route.params.subscribe(params => {
this.getItem(params['id']);
});
}
getItem = (id) => {
this.itemsService.getItem(id).subscribe(res => {
console.log(res);
this.item = res;
console.log(this.item);
});
}
And the service it uses for calls:
import { Injectable } from '#angular/core';
import { AngularFirestore, AngularFirestoreDocument } from '#angular/fire/firestore';
#Injectable({
providedIn: 'root'
})
export class ItemsService {
constructor(
private firestore: AngularFirestore
)
getItem(id) {
return this.firestore.collection('items').doc(id).snapshotChanges();
}
}
The log I get for console.log(this.item) is undefined. Calling this.item in the console returns the same. I am unsure of how to proceed and would appreciate any guidance. Logging res in the console returns a byzantine object. Perhaps that's how I access the item, but if so, why is it not saved in this.item and how do I access the item's values?
snapshotChanges returns an observable of actions, not the actual value.
You should extract the value with action.payload.doc.data():
So your code should look like the following example.
getItem(id) {
return this.firestore.collection('items').doc(id).snapshotChanges()
.pipe(
map(actions => actions.map(a => {
const data = a.payload.doc.data();
const id = a.payload.doc.id;
return { id, ...data };
})
);
}
Or you can use valueChanges of doc.
getItem(id) {
return this.firestore.collection('items').doc(id).valueChanges();
}
I got problem with angular component.
When I make my component with selector, it works as expected: execute httpget, and render photo with title.
But in console I got two errors:
ERROR TypeError: "_co.photo is undefined"
View_PhotoHolderComponent_0 PhotoHolderComponent.html:2
and
ERROR CONTEXT
...
PhotoHolderComponent.html:2:8
View_PhotoHolderComponent_0 PhotoHolderComponent.html:2
I got html:
<div class="photo-holder">
<h2>{{photo.title}}</h2>
<img src="{{photo.url}}">
</div>
and ts:
import { Component, OnInit } from '#angular/core';
import { Photo } from './photo'
import { PhotoDeliveryService } from '../photo-delivery-service.service'
#Component({
selector: 'app-photo-holder',
templateUrl: './photo-holder.component.html',
styleUrls: ['./photo-holder.component.css']
})
export class PhotoHolderComponent implements OnInit {
photo:Photo
constructor( private photoService : PhotoDeliveryService) {
}
ngOnInit() {
this.photoService.getRandomPhoto().subscribe((data: Photo) => this.photo = {...data})
}
}
and service :
import { Injectable } from '#angular/core';
import { HttpClient } from '#angular/common/http';
import { Photo } from './photo-holder/photo'
#Injectable({
providedIn: 'root'
})
export class PhotoDeliveryService {
value : Number
url : string
constructor(private http: HttpClient) {
this.url = "https://jsonplaceholder.typicode.com/photos/";
this.value = Math.floor(Math.random() * 10) + 1;
}
getRandomPhoto() {
return this.http.get<Photo>(this.getUrl())
}
getUrl(){
return this.url + this.value;
}
}
I suspect that could be made by binding property before query results was returned.
How can I rid off this problem, can I wait for this query, or this is different kind of problem ?
You are getting the error because before your service could resolve, the template bindings are resolved and at that time photo object is undefined.
first thing, you can initialize the photo object but then you might have to detect the changes using ChangeDetectorRef to reflect the value returned by the service.
photo:Photo = {
title:'',
url:''
};
constructor( private photoService : PhotoserviceService, private cdr:ChangeDetectorRef) {
}
ngOnInit() {
this.photoService.getRandomPhoto().subscribe((data: Photo) => {
this.photo = data;
this.cdr.detectChanges();
});
}
My code was working previously, displaying the data from an API correctly after using the reduce function.
I pulled my files from github on a new machine and suddenly I'm getting this error. Any help is greatly appreciated, as I've tried what I can to figure out what I've done wrong.
"ERROR TypeError: tickets.reduce is not a function
at SectionDashboardComponent.push../src/app/Sections/section-
dashboard/section-
dashboard.component.ts.SectionDashboardComponent.getTicketData (section-dashboard.component.ts:30)"
Here's the ts page where this error seems to be occurring:
import { Component, OnInit } from '#angular/core';
import { freshServiceService } from
'src/app/Services/freshservice.service';
import { Ticket } from 'src/app/Domain/Ticket';
#Component({
selector: 'app-section-dashboard',
templateUrl: './section-dashboard.component.html',
styleUrls: ['./section-dashboard.component.css']
})
export class SectionDashboardComponent implements OnInit {
constructor(private _freshServiceService: freshServiceService) { }
private ticketCounts: number[];
private ticketResponders: string[];
ngOnInit() {
this._freshServiceService.fetchTickets().subscribe
(
data =>
{
console.log(data);
this.getTicketData(data);
}
);
}
private getTicketData(tickets: Ticket[]): void {
const mappedTickets = tickets.reduce((x, y) => {
{x[y.responder_name] = x[y.responder_name] + 1 || 1};
return x;
}, []);
this.ticketResponders = Object.keys(mappedTickets);
this.ticketCounts = Object.values(mappedTickets);
console.log(this.ticketResponders);
console.log(this.ticketCounts);
}
}
I'm getting this error and i'm new to angular 2 so i'm not 100% sure on how to resolve the issue, i'm connecting to a test API to return a javascript object which includes some dummy data. But my "this.onGet()" function is telling me that the supplied parameter does not match any signature of call target and i can't seem to figure out why.
(Essentially i'm just trying to populate the orderInfo array with the information from the API so i can use it across multiple page)
Any help appreciated :)
App.component.ts
import { Component, OnInit } from '#angular/core';
import { DetailsService } from './details.service';
#Component({
selector: 'app-root',
templateUrl: './app.component.html',
styleUrls: ['./app.component.css'],
providers: [DetailsService]
})
export class AppComponent implements OnInit {
orderInfo = [
{
name: 'Test'
}
];
constructor(private detailsService: DetailsService) {
}
ngOnInit() {
this.onGet();
}
onGet(name: string) {
this.detailsService.getDetails()
.subscribe(
(orderData: any[]) => {
this.orderInfo.push({
name: name
});
console.log(orderData);
}
);
}
}
details.service.ts
import {Injectable} from '#angular/core';
import { Http, Response } from '#angular/http';
import 'rxjs/Rx';
#Injectable()
export class DetailsService {
constructor(private http: Http) {}
getDetails() {
return this.http.get('http://swapi.co/api/people/1/?format=json', '')
.map(
(response: Response) => {
const orderData = response.json();
return orderData;
}
);
}
}
The signature of http get method is
get(url: string, options?: RequestOptionsArgs) : Observable<Response>
You are passing a extra string parameter
getDetails() {
///////////////removed below single quotes
return this.http.get('http://swapi.co/api/people/1/?format=json')
.map(
(response: Response) => {
const orderData = response.json();
return orderData;
}
);
Look into your
ngOnInit() {
this.onGet(); //////////nothing passed
}
where as your method signature is onGet(name:string) you are not passing anything as above
Your OnGet function is expecting a string parameter, which is not supplied while calling from ngOnInit.
I try to retrieve data from my Firebase and it works, but JUST for console.log().
I can't return a value into a var...
As I'm working with Angular 2 & Typescript I have
a Service:
import {Injectable} from "angular2/core";
import 'rxjs/Rx';
import {Observable} from "rxjs/Observable";
declare var Firebase: any;
#Injectable()
export class DataService {
getAllData() {
const firebaseRef = new Firebase('https://XYZ.firebaseio.com/path/user')
firebaseRef.on("value", function (snapshot) {
console.log(snapshot.val()); // THIS WORKS!
return snapshot.val(); // THIS DOES NOT WORK!
});
}
and a Component:
#Component({
templateUrl: 'templates/user.tpl.html',
providers: [DataService],
})
export class UserComponent implements OnInit{
userData: any;
constructor(private _dataService: DataService){}
ngOnInit():any {
this.userData = this._dataService.getAllData();
console.log(this.userData); // THIS DOES NOT WORK: UNDEFINED
}
If i run that, I get nothing for my userData var... And I can't figure how to fix that. I thought I would need an Observable but I failed, whatever I tried to do...
Can someone help?
You need to wrap your call into an observable since Firebase is event-driven:
getAllData() {
const firebaseRef = new Firebase('https://XYZ.firebaseio.com/path/user')
return Observable.create((observer) => {
firebaseRef.on("value", function (snapshot) {
console.log(snapshot.val());
observer.next(snapshot.val());
});
});
}
This way you will be able to receive value by subscribing on the returned observable:
ngOnInit():any {
this._dataService.getAllData().subscribe(data => {
this.userData = data;
});
}