I have a real-time database on Firebase, and I want to retrieve records from this database using parameters.
For example, in the hierarchy you see, I want to get the data using the uID value. How can I do that?
UPDATE
https://javebratt.com/firebase-objects-ionic-2-app/
I have tried the heading "Read Firebase Data" in the article on the link I gave, but I do not know how to update the code if it is written for Ionic 2.
Here is the code I wrote,
import { Component } from '#angular/core';
import { IonicPage, NavController, NavParams } from 'ionic-angular';
import { Post } from '../../models/models/post';
import { AngularFireDatabase } from 'angularfire2/database';
import { Storage } from '#ionic/storage';
#IonicPage()
#Component({
selector: 'page-profile',
templateUrl: 'profile.html',
})
export class ProfilePage {
public posts: Post[];
public uID: string;
constructor(public navCtrl: NavController,
public navParams: NavParams,
private db: AngularFireDatabase,
private storage: Storage) {
this.storage.get('uID').then((val) => {
console.log('uID: ' + val);
this.uID = val;
console.log('this.uID: ' + this.uID);
this.db.list<Post>('/Post/',
ref => ref.orderByChild('uID').equalTo(this.uID)).valueChanges().subscribe(t => {
this.posts = t;
})
});
}
ionViewDidLoad() {
console.log('ionViewDidLoad ProfilePage');
}
}
According to the article I had to do create a variable which is type of "Reference", but with AngularFireDatabase it is not possible to make such a definition.
How do I update this definition in Ionic 3?
UPDATE
I added some codes;
db.database.ref('/User/').on('value', res => {
console.log("Try Val: " + res.val)
console.log("Try Key: " + res.key)
console.log("Try Child: " + res.child)
});
And outputs;
Try Val: function () {
util_1.validateArgCount('DataSnapshot.val', 0, 0, arguments.length);
return this.node_.val();
}
Try Key: User
Try Child: function (childPathString) {
util_1.validateArgCount('DataSnapshot.child', 0, 1, arguments.length);
// Ensure the childPath is a string (can be a number)
childPathString = String(childPathString);
validation_1.validatePathString('DataSnapshot.child', 1, childPathString, false);
var childPath = new Path_1.Path(childPathString);
var childRef = this.ref_.child(childPath);
return new DataSnapshot(this.node_.getChild(childPath), childRef, PriorityIndex_1.PRIORITY_INDEX);
}
UPDATE
I could get data, but it's not clear answer.
Firebase records all data with a key value. I also added this key value after the "/ Post /" value as the data path. For example "/ Post / -1ersksnu0nsw1 /".
Here is the code;
db.database.ref('/User/-L88gtymS5pS3KWtZrmI').on('value', res => {
console.log(res.val().email)
});
And I could get true value, but I still do not know how to do this according to the columns of their records.
EUREKA!
db.database.ref('/User/').orderByChild('uID').equalTo(this.uID).once('value', (snapshot) => {
console.log(snapshot.val().email)
})
This code will do that.
You can checkout this tutorial. It create a chat app but it may help you on what you want to to.
firebase.database().ref('/Post/').on('value', resp => {
console.log(resp)
});
Related
I want to display the ngx-wheel using api but I'm having trouble displaying the data.
Here my Service :
import { Injectable } from '#angular/core';
import { HttpClient, HttpHeaders } from '#angular/common/http';
#Injectable({
providedIn: 'root'
})
export class RestServices {
restEndpoint:string = 'https://gorest.co.in/public/v2/users'
constructor(
private httpClient: HttpClient
) { }
async getServiceId() {
const httpOptions = {
headers: new HttpHeaders({
'Content-Type': 'application/json',
})
}
return this.httpClient.get<any[]>(this.restEndpoint, httpOptions)
}
Here my Component :
private subscription: Subscription | undefined;
items: any = []
ngOnInit(): void {
this.subscription = this._restService.getServices()
.subscribe((res:any)=>{
let item = res
this.items = item.map((v:any) => ({
text: v.name,
id: v.id,
textFillStyle: "white",
textFontSize: "16"
}));
})
}
ngOnDestroy(): void {
this.subscription?.unsubscribe()
}
Here for html
<ngx-wheel #wheel [width]='350' [height]='350' [spinDuration]='8' [disableSpinOnClick]='true' [items]='items'
[innerRadius]='10' [spinAmount]='10' [textOrientation]='textOrientation' [textAlignment]='textAlignment'
pointerStrokeColor='black' pointerFillColor='white' [idToLandOn]='idToLandOn' (onSpinStart)='before()'
(onSpinComplete)='after()'>
I hope to find the answer here. Thank you
First, you don't need await, async and ,toPromise()... remove them and simply return
return this.httpClient.get<any[]>(this.restEndpoint, httpOptions);
inside your component you should use your constructor only for simple data initialization: if you have to consume a rest api it is a better approach to move that piece of code inside the ngOnInit method:
items: any[] = []
constructor(private restService: RestService){}//dependency injection
ngOnInit(): void {
this.restService.getServiceId().subscribe(response => {
console.log('response success: ', response);
this.items = response; //this may change a little based on your api
console.log('items: ', this.items);
}, errorLog => {
console.log('response error: ', errorLog)
});
}
The above solution is valid, you can enrich it by adding a *ngIf="isLoaded" on your html element and set to true the isLoaded INSIDE subscribe method. but if you prefer you can do the following in the component.ts
items$: Observable<any> = EMPTY;
constructor(private restService: RestService){}//dependency injection
ngOnInit(): void {
this.items$ = this.restService.getServiceId();
}
then, in your html it would change to the following:
<ngx-wheel #wheel *ngIf="items$ | async as items" [width]='350' [height]='350' [spinDuration]='8' [disableSpinOnClick]='true' [items]='items'
[innerRadius]='10' [spinAmount]='10' [textOrientation]='textOrientation' [textAlignment]='textAlignment'
pointerStrokeColor='black' pointerFillColor='white' [idToLandOn]='idToLandOn' (onSpinStart)='before()'
(onSpinComplete)='after()'>
I have an component where i am adding a new object called customer by calling the api like this:
public onAdd(): void {
this.myCustomer = this.customerForm.value;
this.myService.addCustomer(this.myCustome).subscribe(
() => { // If POST is success
this.callSuccessMethod();
},
(error) => { // If POST is failed
this.callFailureMethod();
},
);
}
Service file:
import { HttpClient } from '#angular/common/http';
import { Injectable } from '#angular/core';
import { Observable, Subject } from 'rxjs';
import {ICustomer } from 'src/app/models/app.models';
#Injectable({
providedIn: 'root',
})
export class MyService {
private baseUrl : string = '....URL....';
constructor(private http: HttpClient) {}
public addCustomer(customer: ICustomer): Observable<object> {
const apiUrl: string = `${this.baseUrl}/customers`;
return this.http.post(apiUrl, customer);
}
}
As shown in component code, i have already subscribed the api call like this:
this.myService.addCustomer(this.myCustome).subscribe(
() => { // If POST is success
.....
},
(error) => { // If POST is failed
...
},
);
But,I want to subscribe the results in another component, I have tried like this:
public getAddedCustomer() {
this.myService.addCustomer().subscribe(
(data:ICustomer) => {
this.addedCustomer.id = data.id; <======
}
);
}
I am getting this lint error: Expected 1 arguments, but got 0 since i am not passing any parameter.
What is the right approach to subscribe the api call in other components? after POST operation.
Because i want to get added object id for other functionality.
Well it totally depends on the design of your application and the relation between components. You can use Subjects for multicasting the data to multiple subscribers.
import { HttpClient } from '#angular/common/http';
import { Injectable } from '#angular/core';
import { Observable, Subject } from 'rxjs';
import { ICustomer } from 'src/app/models/app.models';
#Injectable({
providedIn: 'root',
})
export class MyService {
private baseUrl : string = '....URL....';
private latestAddedCustomer = new Subject();
public latestAddedCustomer$ = this.latestAddedCustomer.asObservable()
constructor(private http: HttpClient) {}
public addCustomer(customer: ICustomer): Observable<object> {
const apiUrl: string = `${this.baseUrl}/customers`;
return this.http.post(apiUrl, customer).pipe(map((data) => this.latestAddedCustomer.next(data)));
}
}
and subscribing to the subject as follows
this.latestAddedCustomer$.subscribe()
should get you the latest added customer details. Even though i would not do this the way its written. I would basically write a seperate service to share the data between the components or would write a cache service if its used across the application. But the idea here is to use the concept of Subjects. You can read more about it Here
I have a contentful service like so..
import { Injectable } from '#angular/core';
import { createClient, Entry } from 'contentful';
import { BehaviorSubject } from 'rxjs/BehaviorSubject';
const CONFIG = {
space: '<spaceid>',
accessToken: '<accesstoken>',
contentTypeIds: {
programItems: 'programItem'
}
};
#Injectable()
export class ContentfulService {
private cdaClient = createClient({
space: CONFIG.space,
accessToken: CONFIG.accessToken
});
public weekNumber = new BehaviorSubject<any>(1);
constructor() { }
// Get all the program items
getProgramItems(query?: object): Promise<Entry<any>[]> {
return this.cdaClient.getEntries(Object.assign({
content_type: CONFIG.contentTypeIds.programItems
}, query))
.then(res => res.items);
}
}
but I only want to bring in the programItems sys.ids in the contentful documentation.. you can modify api calls and return only certain values like this modify api calls
https://cdn.contentful.com/spaces/<space_id>/entries/
?select=fields.productName,fields.price
&content_type=<content_type_id>
but Im not sure how I would implement the same thing, the way they do angular calls.. I could just do a http request but I would prefer to keep it the same way as I have done above
any help would be appreciated
You add a select property to your getEntries call.
// Get all the program items
getProgramItems(query?: object): Promise<Entry<any>[]> {
return this.cdaClient.getEntries(Object.assign({
content_type: CONFIG.contentTypeIds.programItems,
select: 'sys.id'
}, query))
.then(res => res.items);
}
You can read the full documentation, including javascript snippets, here: https://www.contentful.com/developers/docs/references/content-delivery-api/#/reference/search-parameters/select-operator/query-entries/console/js
Continue to the Using angular material 2 table to display the result from backend based on user's current location
My purpose for this code is when user enter the site, it will try to ask user the current location. Once my front end get current lat/lon, it will pass to backend to get the nearest restaurant based on user's location, and using angular material table to display it. But when I testing on Chrome, I got weird behavior, the home page will not display the result immediately on the first time, try refresh, doesn't work, the only way make it works is switch another tab, and back to this one, it will display the result in angular material table.
Here is the code for home.component.ts
import { Component, OnInit } from '#angular/core';
import { Http, Response, URLSearchParams } from '#angular/http';
import { DataSource } from '#angular/cdk';
import { BehaviorSubject } from 'rxjs/BehaviorSubject';
import { Observable } from 'rxjs/Observable';
import 'rxjs/add/operator/startWith';
import 'rxjs/add/observable/merge';
import 'rxjs/add/operator/map';
import 'rxjs/add/observable/frompromise';
import { Restaurant } from '../restaurant/restaurant';
import { Category } from '../category/category';
import { RestaurantService } from '../restaurant/restaurant.service';
#Component({
selector: 'app-home',
templateUrl: './home.component.html',
styleUrls: ['./home.component.css']
})
export class HomeComponent implements OnInit {
displayedColumns = ['Id', 'Name', 'Category', 'Address', 'City'];
dataSource: ExampleDataSource | null;
constructor(http: Http) {
//this.exampleDatabase = new ExampleHttpDatabase(http, this.location);
this.dataSource = new ExampleDataSource(http);
}
ngOnInit() {
this.dataSource.connect();
}
}
export class ExampleDataSource extends DataSource<Restaurant> {
private url = 'api/search/location';
private params = new URLSearchParams();
private lat;
private lon;
constructor(private http: Http) {
super();
}
/** Connect function called by the table to retrieve one stream containing the data to render. */
connect(): Observable<Restaurant[]> {
// var location;
// if (navigator.geolocation){
// var options = {timeout: 60000};
// location = navigator.geolocation.getCurrentPosition((position)=>{
// return position;
// },(err) =>{
// console.log("Error")
// }, options);
// }
// console.log("Locations: " + location);
var result = this.getCurrentLocation().then((res) =>
{
return res;
});
return Observable.fromPromise(result);
}
disconnect() { }
getPosition = () => {
var latitude, longitude;
return new Promise((resolve, reject) => {
navigator.geolocation.getCurrentPosition((position) => {
resolve(position.coords);
}, (err) => {
reject(err);
});
})
}
async getCurrentLocation(): Promise<Restaurant[]> {
let coords = await this.getPosition();
this.lat = coords['latitude'];
this.lon = coords['longitude'];
this.params.set('lat', this.lat);
this.params.set('lon', this.lon);
var result = this.http.get(this.url, { search: this.params }).map(this.extractData);
return await result.toPromise();
}
extractData(result: Response): Restaurant[] {
return result.json().map(restaurant => {
return {
id: restaurant.id,
name: restaurant.restaurant_name,
category: restaurant.category.map(c => c.categoryName).join(','),
address: restaurant.address.address,
city: restaurant.address.city.cityName
}
});
}
}
I don't know what I did wrong.. can someone help me? For the full code, please see https://github.com/zhengye1/Eatr/tree/dev
Finally solved....
All I need to do just change ngOnInit on HomeComponent class to following
async ngOnInit() {
await this.dataSource.connect();
}
and it works.. don't know why...
I am developing an website that needs to be logged in with Facebook account. I am using Angular 2 and, of course, TypeScript. It works But not exactly what I wanted. I can't take back the user's information.
Let's go to the code:
import {Component} from 'angular2/core';
import {Main} from './pages/main/main';
declare const FB: any;
#Component({
selector: 'my-app',
templateUrl: 'app/app.html',
directives: [Main]
})
export class AppComponent implements OnInit {
token: any;
loged: boolean = false;
user = { name: 'Hello' };
constructor() { }
statusChangeCallback(response: any) {
if (response.status === 'connected') {
console.log('connected');
} else {
this.login();
}
}
login() {
FB.login(function(result) {
this.loged = true;
this.token = result;
}, { scope: 'user_friends' });
}
me() {
FB.api('/me?fields=id,name,first_name,gender,picture.width(150).height(150),age_range,friends',
function(result) {
if (result && !result.error) {
this.user = result;
console.log(this.user);
} else {
console.log(result.error);
}
});
}
ngOnInit() {
FB.getLoginStatus(response => {
this.statusChangeCallback(response);
});
}
}
Basically, When the page loads I check if the user is logged in to Facebook, if not, I call the login method. The me method is used to fetch the users information, like its name, first name etc. When I logged in condition browser console print the following line:
Object {id: "666", name: "Paulo Henrique Tokarski Glinski", first_name: "Paulo", gender: "male", picture: Object…}
Everything ok! But I want to get that Object and put into a User object! Something like that:
me method:
this.user = result;
console.log(this.user);
But the user just exists inside the method. If I print it outside, its returns nothing.
I just want to print the users name etc. at the website page. I did almost the same thing with Angular JS and worked well.
Please! Help me!
you can use fat arrow functions to use the same context ...
login() {
FB.login((result: any) => {
this.loged = true;
this.token = result;
}, { scope: 'user_friends' });
}
For the facebook javascript SDK, You just add the following line in your index.html
<script src="//connect.facebook.net/en_US/sdk.js"></script>
and in ngOnInit() :
`FB.init({
appId : 'your-app-id',
cookie : false,
xfbml : true, // parse social plugins on this page
version : 'v2.5' // use graph api version 2.5
});`
Angular 2 Service level implementation
import {Injectable} from '#angular/core';
import { Location } from '#angular/common';
import { Http, Response, Headers, RequestOptions,URLSearchParams } from '#angular/http';
import { Observable } from 'rxjs/Observable';
import { ConfigService } from "app/core/services/config.service";
import 'rxjs/add/observable/throw';
import 'rxjs/add/operator/map';
import 'rxjs/add/operator/catch';
#Injectable()
export class AuthService {
constructor(private http: Http,
private configProvider:ConfigService) {
}
authenticateFacebook(){
window.location.href = 'https://www.facebook.com/v2.9/dialog/oauth?client_id='+
this.configProvider.config.facebook.clientId +
'&redirect_uri='+ this.configProvider.config.facebook.redirectURI + '&scope=public_profile';
}
getAccessToken(authenticationCode: string){
var authProviderUrl = 'https://graph.facebook.com/v2.9/oauth/access_token';
var authParameters = {
client_id: this.configProvider.config.facebook.clientId,
redirect_uri: this.configProvider.config.facebook.redirectURI,
client_secret: this.configProvider.config.facebook.clientSecret,
code: authenticationCode
};
var params = [];
for (var k in authParameters) {
params.push(k + '=' + authParameters[k]);
}
var authOpenURI = authProviderUrl + '?' + params.join('&');
return this.http.get(authOpenURI)
.map(res => res.json())
.catch(err => Observable.throw(err));
}
getUserFacebookProfile(accessToken:string):Observable<any>{
var fields = ['id', 'email', 'first_name', 'last_name', 'link', 'name','picture.type(small)'];
var graphApiUrl = 'https://graph.facebook.com/v2.5/me?fields=' + fields.join(',');
return this.http.get(graphApiUrl+'&access_token='+accessToken+'')
.map(res => res.json())
.catch(err => Observable.throw(err));
}
Caller level function, this code will be in the component of your redirect URI
//Facebook authentication check
if (window.location.href.indexOf("code") > -1){
var code = window.location.href.substring(window.location.href.indexOf("?") + 1).split('&')[0].split('=')[1];
this.getFaceBookProfile(code);
}
//Get profile from facebook
getFaceBookProfile(code:string){
this.authService.getAccessToken(code).subscribe(oathAccessData => {
this.authService.getUserFacebookProfile(oathAccessData.access_token).subscribe(profile => {
this.userProfile = new UserProfile(profile.name,profile.email, profile.picture.data.url,"facebook",
profile.id);},err => { console.log(err); });},err => { console.log(err);});
this.router.navigate(['/dashboard']);
}
this has a bunch of magic involved. Does it help if you capture the class's this in a variable and use that in the callbacks (so as to avoid caring what their this is)?
e.g.
login() {
var self = this;
FB.login(function(result) {
self.loged = true;
self.token = result;
}, { scope: 'user_friends' });
}