Firebase doesn't return value (Angular 2) - javascript

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

Related

Have realtime updates for a single Firestore document

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

How to extract values from BehaviouralSubject in Angular

I created an Account Service, for my angular application, and it handles the Login and logout. and this works perfectly. But I am having an issue, I used BehaviourSubject Observables to render the variables.
I am trying to retrieve the loginstatus value, and the username string on the component using the service, but the observable is returning an object, and I am having problems extracting the string out of the object. How can I extract variable types from Behavioursubject observables?
The Account Service...
import { Injectable } from '#angular/core';
import { HttpClient } from '#angular/common/http';
import { Observable, Subject, BehaviorSubject } from 'rxjs';
import { map } from 'rxjs/operators';
import { Router } from '#angular/router';
#Injectable({
providedIn: 'root'
})
export class AccountService {
private baseUrlLogin:string = "/api/account/login";
private loginStatus = new BehaviorSubject<boolean>
(this.checkLoginStatus());
private userName = new BehaviorSubject<string> localStorage.getItem['username']);
constructor(
private http:HttpClient,
private router: Router
){}
login(username:string, password:string){
return this.http.post<any>(this.baseUrlLogin,{username, password}).pipe(
map(result => {
if(result && result.token){
localStorage.setItem('loginStatus', '1');
localStorage.setItem('username', result.username),
}
return result;
})
);
}
logout(){
this.loginStatus.next(false);
localStorage.setItem('loginStatus', '0');
localStorage.removeItem('username'),
localStorage.clear();
//now redirect to the login page...
this.router.navigate(['/login']);
console.log("logged out successfully...");
}
get isLoggedIn(){
return this.loginStatus.asObservable();
}
get currentUserName(){
return this.userName.asObservable();
}
}
The Component Using the Service
import { Component, Input, OnInit } from '#angular/core';
import { AccountService } from 'src/app/services/account.service';
import { Observable } from 'rxjs';
#Component({
selector: 'app-home',
templateUrl: './home.component.html',
styleUrls: ['./home.component.css']
})
export class HomeComponent implements OnInit {
pgtitle:string = "SCB Dashboard";
loginStatus$ : Observable<boolean>;
username$ : Observable<string>;
constructor(
private acc:AccountService
){}
ngOnInit() {
this.loginStatus$ = this.acc.isLoggedIn;
this.username$ = this.acc.currentUserName;
console.log(this.loginStatus$); //here it ruturns an object
console.log(this.username$); //and here too...
}
}
The console.log() returns an object, but how do I retrieve the variables, and work with them in the controller, since they are of type observable?
Rxjs BehaviourSubject has an asObservable() method, you can generate your observable from it
let sourceSubject = new BehaviourSubject();
let source$ = sourceSubject.asObservable();
source$.subscribe(result => // Your data)
// Update the BehaviourSubject
sourceSubject.next(newValue);
You need to subscribe to the observable to get the value out of it:
this.loginStatus$.subscribe(value => {
console.log(value); // access value
});
try this:
get isLoggedIn(){
return this.loginStatus.value;
}
get currentUserName(){
return this.userName.value;
}
This should also work:
ngOnInit() {
this.loginStatus$ = this.acc.isLoggedIn.pipe(
tap(status => console.log(status))
);
this.username$ = this.acc.currentUserName.pipe(
tap(userName => console.log(userName))
);
}
Assuming that you subscribed somewhere, such as with an async pipe.

return json object with jsonp api call

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

Angular Firebase Querying?

This is my .ts file to query the angular firebase database
import { Component, OnInit } from '#angular/core';
import { AngularFireDatabase, FirebaseListObservable, FirebaseObjectObservable } from 'angularfire2/database';
#Component({
selector: 'app-candidate-reg-success',
templateUrl: './candidate-reg-success.component.html',
styleUrls: ['./candidate-reg-success.component.css']
})
export class CandidateRegSuccessComponent implements OnInit {
result:any;
items: FirebaseListObservable<any[]>;
constructor(db: AngularFireDatabase) {
debugger;
this.items=db.list('/candidates_list',{
query:{
orderByChild:'email',
equalTo:'pranavkeke#gmail.com'
}
});
this.items.subscribe(quiredItems=>{
this.result=quiredItems;
console.log(this.result);
console.log(this.result.FirstName);
// console.log();
});
// debugger;
// const rootRef=firebase.database().ref();
// const mail=rootRef.child('candidates_list').orderByChild('email').equalTo('pranavkeke#gmail.com');
// console.log(mail);
}
ngOnInit() {
}
}
I am getting the user with specified criteria, but I want only the firstname of the user.The problem is with this one
console.log(this.result.FirstName);
The result variable holds all the json data from firebase, butI want only firstname. But in console it shows undefined. How can be it solved? Please help me. Thanks in advance.
try to transform each item in the FirebaseListObservable first:
this.items=db.list('/candidates_list',{
query:{
orderByChild:'email',
equalTo:'pranavkeke#gmail.com'
}})
.map(item => item.FirstName) as FirebaseListObservable<any[]>;

How to take the data from the angular2 firebase data.?

I have candidates_list table in angular2 firebase, but I am not getting the value from it.
My ts file is this
import { Component, OnInit,Input } from '#angular/core';
import { AngularFireDatabase, FirebaseListObservable, FirebaseObjectObservable } from 'angularfire2/database';
import * as firebase from 'firebase';
import { FirebseService } from "app/firebse.service";
#Component({
selector: 'app-candidate-reg-complete',
templateUrl: './candidate-reg-complete.component.html',
styleUrls: ['./candidate-reg-complete.component.css']
})
export class CandidateRegCompleteComponent implements OnInit {
content:any;
item: FirebaseObjectObservable<any>;
constructor(private db: AngularFireDatabase,
private firebaseService:FirebseService) {
this.item = db.object('candidates_list');
}
ngOnInit() {
}
upload(documents){
// let file=user.files[0];
// console.log(file);
// console.log(file.name);
let storageRef=firebase.storage().ref();
for(let selectedFile of[(<HTMLInputElement>document.getElementById('file')).files[0]]){
let path='/resumes/'+selectedFile.name;
let iRef=storageRef.child(path);
iRef.put(selectedFile).then((snapshot)=>{
debugger;
documents.resume=selectedFile.name;
documents.path=path;
var Userid=localStorage.getItem('user');
console.log(documents);
let content=this.db.object('/candidates_list/'+Userid);
console.log(content);
// this.db.object('/candidates_list/'+Userid).update(documents);
localStorage.setItem('resume',documents.path);
})
}
}
}
The problem is with this code
let content=this.db.object('/candidates_list/'+Userid);
console.log(content);
When I try to console this value, the output is like this..
FirebaseObjectObservable {_isScalar: false, $ref: U, source: FirebaseObjectObservable, operator: ObserveOnOperator}
Not conoling the exact content, so any solution for this problem?
You need to subscribe to the observable. Try this:
let content = this.db.object('/candidates_list/'+Userid)
content.subscribe(data => {
console.log(data)})

Categories