I am currently working on a project where there are two types of users: Drivers and Passengers. I am using Ionic Framework and Firebase Database ad Authentication. The Passengers are able to send requests to the drivers and the drivers are able to see these requests. I am currently working on the driver home page and creating a platform that lists the passenger's/customer's data and requests. I really want to user ionic modals to keep the information organized but I am unsure on how to go about this. I went ahead and attached the HTML and Javascript files for the Driver Home page and the modal page. Any help is extremely appreciated. This is my first time using Firebase and I am extremely lost.
My Database Structure
Driver Home Page
import { Component } from '#angular/core';
import { IonicPage, NavController, NavParams, ModalController, Modal } from 'ionic-angular';
import { DriverHomePage } from '../driver-home/driver-home';
import { CustomerModalPage } from '../customer-modal/customer-modal';
import { AngularFireAuth } from 'angularfire2/auth';
import { AngularFireDatabase, FirebaseListObservable } from 'angularfire2/database';
import * as firebase from 'firebase';
/**
* Generated class for the DriverHomePage page.
*
* See https://ionicframework.com/docs/components/#navigation for more info on
* Ionic pages and navigation.
*/
#IonicPage()
#Component({
selector: 'page-driver-home',
templateUrl: 'driver-home.html'
})
export class DriverHomePage {
const custRef = firebase.database().ref().child('User').orderByChild('type').equalTo('customer').once('value', function(snapshot) {
snapshot.forEach(function(child) {
var newCustomer = child.val();
var firstName=child.val().firstName;
var lastName=child.val().lastName;
var phone=child.val().phone;
var location = child.val().location;
var numOfPassengers = child.val().numOfPassengers;
var payment = child.val().payment;
});
});
constructor(private modalCtrl: ModalController, private afAuth: AngularFireAuth, private afDatabase: AngularFireDatabase, public navCtrl: NavController, public navParams: NavParams) {
}
openModal(){
//const custData
/* const custModal: Modal = this.modalCtrl.create('CustomerModalPage');
custModal.present();
custModal.onDidDismiss();*/
}
ionViewDidLoad() {
console.log('ionViewDidLoad DriverHomePage');
}
}
<!--
Generated template for the DriverHomePage page.
See http://ionicframework.com/docs/components/#navigation for more info on
Ionic pages and navigation.
-->
<ion-header>
<ion-navbar>
<button ion-button menuToggle>
<ion-icon name="menu"></ion-icon>
</button>
<ion-title>driver-home</ion-title>
</ion-navbar>
</ion-header>
<ion-content padding>
<button (click)"openModal()">{{ custRef.firstName }} {{ custRef.lastName }}</button>
</ion-content>
Modal
import { Component } from '#angular/core';
import { IonicPage, NavController, NavParams, ViewController } from 'ionic-angular';
import { AngularFire, FirebaseObjectObservable } from 'angularfire2';
import { AngularFireDatabase } from 'angularfire2/database';
import * as firebase from 'firebase';
/**
* Generated class for the CustomerModalPage page.
*
* See https://ionicframework.com/docs/components/#navigation for more info on
* Ionic pages and navigation.
*/
#IonicPage()
#Component({
selector: 'page-customer-modal',
templateUrl: 'customer-modal.html',
})
export class CustomerModalPage {
const custRef = firebase.database().ref().child(`User`).orderByChild('type').equalTo('customer').on('value', function(snapshot) {
snapshot.forEach(function(child) {
var datas = child.val();
var firstName=child.val().firstName;
var lastName=child.val().lastName;
var phone=child.val().phone;
var location = child.val().location;
var numOfPassengers = child.val().numOfPassengers;
var payment = child.val().payment;
});
});
constructor(private fb: AngularFire, private viewCtrl: ViewController, public navCtrl: NavController, public navParams: NavParams) {
}
acceptRequest(){
}
closeModal() {
this.viewCtrl.dismiss();
}
/*ionViewDidLoad() {
console.log('ionViewDidLoad CustomerModalPage');
}*/
ionViewWillLoad(){
//const data = this.navParams.get('data');
console.log();
}
}
<!--
Generated template for the CustomerModalPage page.
See http://ionicframework.com/docs/components/#navigation for more info on
Ionic pages and navigation.
-->
<ion-header>
<ion-navbar>
<ion-title>CustomerModalPage</ion-title>
<ion-buttons end>
<button ion-button (click)="closeModal()">Close</button>
</ion-buttons>
</ion-navbar>
</ion-header>
<ion-content padding>
<p>{{ custRef.firstName }}</p>
<p>{{ custRef.lastName }}</p>
<p>{{ custRef.phone }}</p>
<p>{{ custRef.location }}</p>
<p>{{ custRef.numOfPassengers }}</p>
<p>{{ custRef.payment }}</p>
<button (click)="acceptRequest()">Accept</button>
</ion-content>
I see you are using firebase library to access your database and I can also see you are importing angularfire2 too. I strongly recommend you use angularfire2 and avoid using firebase library as this is way easier. You can read more in the angularfire2 docs.
For your question, the best query would be something like this:
this.db.list('/user', ref => ref.orderByChild('type').equalTo('customer'))
.subscribe(users => {
users.forEach(user => {
//Do stuff with each user here.
})
});
Also, remember to inject the correct reference in your component. Your constructor should look like this:
constructor(db: AngularFireDatabase) { }
Related
UPDATE ON BOTTOM
I am trying to show data in an *ngFor that i'm getting from an object that is getting retrieved asynchronously from ionic storage. At the moment i am getting a blank screen.
I have tried multiple things like using async pipes in different manners.
Does anybody know the right way?
Here is my storage service method that is getting called:
public getFlow(flowId:number){
return this.storage.get(FLOWS_KEY).then((flows:Map<number,Flow>)=>{
return flows.get(flowId);
});
}
this returns a Promise<Flow>
this is my component code:
import { Component, OnInit } from '#angular/core';
import { ModalController } from 'ionic-angular';
import { IonicPage, NavController, NavParams } from 'ionic-angular';
import { Flow } from '../../model/Flow';
import { FlowService } from '../../model/services/flowService';
import {CreateTaskPage} from '../create-task/create-task'
import { Task } from '../../model/Task';
#IonicPage()
#Component({
selector: 'page-flow',
templateUrl: 'flow.html',
})
export class FlowPage {
flow;
constructor(public navCtrl: NavController, public navParams: NavParams,private flowService:FlowService,public modalCtrl: ModalController) {
this.flow = this.flowService.getFlow(Number(this.navParams.get("flowId")))
}
ngOnInit(): void {
}
ionViewDidLoad() {
console.log('ionViewDidLoad FlowPage');
}
createTask(){
const modal = this.modalCtrl.create(CreateTaskPage,{flowId:this.flow.flowId});
modal.present();
}
swipe(e,task:Task){
if(e.direction == 2){
console.log("panUp");
task.column--;
}
if(e.direction == 4){
console.log("panDown");
task.column++;
}
}
}
My html:
<ion-content padding>
<div *ngIf="(flow | async)">
<div *ngFor="let col of flow.columns;index as i">
<h2>{{col}}</h2>
<div *ngFor="let task of flow.getTasksFromCol(i)">
<ion-card (swipe)="swipe($event,task)">
<ion-item>
<h2>{{task}}</h2>
<button ion-button item-end clear icon-end>
<ion-icon name='more'></ion-icon>
</button>
<p>{{task}}</p>
</ion-item>
</ion-card>
</div>
</div>
</div>
<ion-fab right bottom>
<button ion-fab color="light"><ion-icon name="arrow-dropleft"></ion-icon></button>
<ion-fab-list side="left">
<button (click)="createTask()" ion-fab><ion-icon name="add-circle"></ion-icon></button>
<button ion-fab><ion-icon name="create"></ion-icon></button>
</ion-fab-list>
</ion-fab>
</ion-content>
Thanks for helping.
UPDATE:
I found one big mistake in my component it now looks like this:
flow:Flow;
constructor(public navCtrl: NavController, public navParams: NavParams,private flowService:FlowService,public modalCtrl: ModalController) {
this.flowService.getFlow(Number(this.navParams.get("flowId"))).then(flow =>{
this.flow = flow;
})
}
i also updated my html but it still isn't working: i now get error:
ERROR TypeError: _co.flow.getTasksFromCol is not a function
at Object.eval [as updateDirectives]
This is weird because this method exists in my Flow Model:
import { Task } from "./Task";
export class Flow {
//PK for 1-n relation with task
flowId:number;
projectName:string;
columns:string[];
tasks: Map<number,Task>;
constructor(flowId:number,projectName:string,columns:string[],tasks:Map<number,Task>){
this.flowId = flowId;
this.projectName = projectName;
this.columns = columns;
this.tasks = tasks;
}
public getTasks(){
return Array.from(this.tasks.values())
}
public getTasksFromCol(colNumber:number){
var tasks = new Array<Task>();
for(let task of Array.from(this.tasks.values())){
if(task.column == colNumber){
tasks.push(task)
}
}
return tasks;
}
}
UPDATE2
i now added this to my service
public getTasksFromCol(flowId:number,colNumber:number){
return this.storage.get(FLOWS_KEY).then((flows:Map<number,Flow>)=>{
var flow:Flow = flows.get(flowId);
var tasks = new Array<Task>();
for(let task of Array.from(flow.tasks.values())){
if(task.column == colNumber){
tasks.push(task)
}
}
return tasks;
});
}
do i just call this in my html page? i'm kinda stuck
I found your mistake.
You have created one variable.
flow:Flow;
You have assigned value to that variable.
this.flow = flow;
Now you need to understand that variable has contains some value related to what you have assigned. So you can't access flow.getTasksFromCol()
Thats the reason you have faced this error.
ERROR TypeError: _co.flow.getTasksFromCol is not a function at Object.eval [as updateDirectives]
Solution:-
Just move this getTasksFromCol() method to service and apply html like following,
I hope it's working. Let try this once and let me know if any error.
I have created a collection that holds the news title, news img, news desc, etc.. I also created the upload method that works fine , uploads the file to storage and saves the path to the collection.
Issues when trying to retrieve the image using getDownloadUrl();
Here are the files
news.component.html
<div class="container-fluid">
<div *ngFor="let item of thenews | async">
<p>
{{ item.newsTitle }} {{ item.newsDesc }}
</p>
<div class="col-md-4">
<img [src]="getImgUrl(item.newsImg)" class="img-responsive">
</div>
</div>
</div>
<div class="container-fluid">
<button mat-raised-button (click)="onLogout()">Logout</button>
</div>
News.component.ts
import { tap } from 'rxjs/operators';
import { AngularFireStorage } from 'angularfire2/storage';
import { AngularFirestoreCollection, AngularFirestoreDocument, AngularFirestore } from 'angularfire2/firestore';
import { Component, OnInit, Injectable } from '#angular/core';
import { AuthService } from './../auth.service';
import { DataService } from '../services/data.service';
import { News } from './../models/newsModel';
import { Observable } from 'rxjs';
#Component({
selector: 'app-news',
templateUrl: './news.component.html',
styleUrls: ['./news.component.css']
})
#Injectable()
export class NewsComponent implements OnInit {
news = {} as News;
newsCol: AngularFirestoreCollection<News>;
thenews: Observable<News[]>;
imgUrl: Observable<any>;
theData: News[] = [];
constructor(public authservice: AuthService, public dataservice: DataService, public afs: AngularFirestore,
private storage: AngularFireStorage) { }
ngOnInit() {
this.newsCol = this.afs.collection<News>('news');
this.thenews = this.newsCol.valueChanges();
}
getImgUrl(img) {
return this.storage.ref(img).getDownloadURL();
}
addNews(news) {
this.dataservice.addNews(news);
}
onLogout() {
this.authservice.onLogout();
}
}
When this is served it runs into an infinite loop. and the site goes hung.
Any help?
getDownloadURL() is a observable method (async function), so you have to wait for the observable to return the value i.e. the url or null if the image is not available
for example
imageUrl: Observable<string | null>;
const ref = this.storage.ref('users/davideast.jpg');
this.imageUrl= ref.getDownloadURL();
in template
<img [src]="profileUrl | async" />
Please refer this link from github
Hope this helps
I am trying to get data of a certain userId out of a firebase Database. But nothing happens? I am creating an AngularFireObject of typ Profile
like this:
profileData: AngularFireObject<Profile>;
There is no error in the code. the HTML is shown how i prefer it but without the data.
the only thing what isn't correct, is that the Methode ionViewDidLoad is shown as unused. But when i pass the code inside the constructor it doesn't has any effect.
Can someone help me with that? Thanks a lot!
import { Component } from '#angular/core';
import {IonicPage, NavController, NavParams, ToastController} from 'ionic-angular';
import {AngularFireAuth} from 'angularfire2/auth';
import {AngularFireDatabase, AngularFireObject} from 'angularfire2/database';
import {Profile} from '../../shared/models/profile';
/**
* Generated class for the HomePage page.
*
* See https://ionicframework.com/docs/components/#navigation for more info on
* Ionic pages and navigation.
*/
#IonicPage()
#Component({
selector: 'page-home',
templateUrl: 'home.html',
})
export class HomePage {
profileData: AngularFireObject<Profile>;
constructor(private afAuth: AngularFireAuth, private afDatabase: AngularFireDatabase, private toast: ToastController,
public navCtrl: NavController, public navParams: NavParams) { }
ionViewDidLoad() {
this.afAuth.authState.subscribe(data => {
console.log(data.uid);
if (data && data.email && data.uid) {
console.log(data.email);
console.log(data.uid);
this.toast.create({
message: `Welcome to The APP, ${data.email}`,
duration: 5000
}).present();
this.profileData = this.afDatabase.object(`/profile/${data.uid}`)
console.log(this.profileData);
} else {
this.toast.create({
message: `Could not find authentication details`,
duration: 3000
}).present();
}
})
}
}
This is the HTML where i would like to load the data.
profile.ts
import { Component } from '#angular/core';
import { IonicPage, NavController, NavParams } from 'ionic-angular';
import {AngularFireAuth} from 'angularfire2/auth';
import {Profile} from '../../shared/models/profile';
import {AngularFireDatabase} from 'angularfire2/database';
#IonicPage()
#Component({
selector: 'page-profile',
templateUrl: 'profile.html',
})
export class ProfilePage {
profile = {} as Profile;
constructor(private afAuth: AngularFireAuth, private afDatabase: AngularFireDatabase,
public navCtrl: NavController, public navParams: NavParams) {
}
/*ionViewDidLoad() {
console.log('ionViewDidLoad ProfilePage');
}*/
createProfile(){
this.afAuth.authState.take(1).subscribe(auth => {
this.afDatabase.object(`profile/${auth.uid}`).set(this.profile)
.then(() => this.navCtrl.setRoot('HomePage'))
})
}
}
<p>Username: {{(profile | async)?.username }}</p>
<p>First Name: {{(profile | async) ?.lastName }}</p>
<p>Last Name: {{(profile | async) ?.firstName}}</p>
There is a issue in the path. your path has a userid which concatenated with profile without separating it using slash (/)
Try to re correct path,
this.afDatabase.object(`/profile/${data.uid}`)
To retrieve data and view, do this way
this.afAuth.authState.subscribe(data => {
if (data && data.email && data.uid) {
this.afDatabase.database.ref().child(`/profile/${data.uid}`).once('value', (snapshot) => {
let result = snapshot.val();
for (let k in result) {
this.profileData = result[k];
}
});
}
});
**This is the html **
<p>Username: {{ profileData.username }}</p>
<p>First Name: {{ profileData.lastName }}</p>
<p>Last Name: {{( profileData.firstName}}</p>
in Homepage.ts
you only have to add take(1) in ligne 27 just like that :
this.afAuth.authState.take(1).subscribe(data => {
I am struggling from last couple days.I am using ionic2/3 angular 2 and wordpress for data.
I am trying to load categories data at home page at first load but i am not getting. In browser it's coming properly and also when i click on menu button entire data is showing properly. I checked all blogs but didn't get any proper solution.
Please help me if any one had same issues and solved.Thanks in advance.
I am attaching my codes here.
enter code here
Home.ts-
import { Component } from '#angular/core';
import { NavController } from 'ionic-angular';
import * as WC from 'woocommerce-api';
#Component({
selector: 'page-home',
templateUrl: 'home.html'
})
export class HomePage {
woocommerce: any;
categories: any[];
// Home=HomePage;
constructor(public navCtrl: NavController) {
this.categories=[];
}
ionViewDidLoad(){
this.getCatData();
}
getCatData(){
this.woocommerce = WC({
url:'http://www.example.com/',
consumerKey: 'ck_7dfe0aec65ahgcdhgcdhcdhf36288d1fa2e4c01',
consumerSecret: 'cs_da53e5b228eb6235bshhcskhc7a68541ad809743'
});
this.woocommerce.getAsync("products/categories").then((data)=>{
console.log(JSON.parse(data.body).product_categories);
this.categories = JSON.parse(data.body).product_categories;
},(err)=>{
console.log(err);
})
}
}
Home.html-
<ion-header>
<ion-navbar color="header">
<ion-buttons left>
<button ion-button menuToggle>
<ion-icon name="menu"></ion-icon>
</button>
</ion-buttons>
<ion-buttons right>
<button ion-button icon-only>
<ion-icon name="search"></ion-icon>
</button>
</ion-buttons>
<ion-title>
KAAIROS EXPORTS
</ion-title>
</ion-navbar>
</ion-header>
<ion-content>
<!-- slider -->
<ion-card>
<ion-slides loop="true" autoplay="false" pager>
<ion-slide *ngFor= "let number of [1,2,3,4,5]"><img src="./assets/img/{{number}}.jpg"/></ion-slide>
</ion-slides>
</ion-card>
<!-- end-slider -->
<!-- <ion-grid> Hi this is second line
</ion-grid> -->
<ion-item *ngFor="let category of categories">
<h2> {{ category.name }} </h2>
</ion-item>
</ion-content>
app.component.ts-
import { TabsPage } from './../pages/tabs/tabs';
import { HomePage } from './../pages/home/home';
import { Component, ViewChild } from '#angular/core';
import { Nav, Platform } from 'ionic-angular';
import { StatusBar } from '#ionic-native/status-bar';
import { SplashScreen } from '#ionic-native/splash-screen';
//import { Menu } from '../pages/menu/menu';
#Component({
templateUrl: 'app.html'
})
export class MyApp {
#ViewChild(Nav) nav: Nav;
// rootPage: any = Menu;
rootPage = TabsPage;
constructor(public platform: Platform, public statusBar: StatusBar, public splashScreen: SplashScreen) {
this.initializeApp();
}
initializeApp() {
this.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.
this.statusBar.styleDefault();
this.splashScreen.hide();
});
}
// go_to_home(){
// this.nav.setRoot(HomePage);
// }
}
app.html-
<ion-menu side="left" [content]="content">
<ion-header>
<ion-toolbar>
<ion-title>Menu</ion-title>
</ion-toolbar>
</ion-header>
<ion-content>
<!-- <ion-list>
<!-- <ion-item (click)="go_to_home()" menuClose>
Home
</ion-item> -->
<!-- <ion-item (click)="go_to_about()" menuClose>
About
</ion-item> -->
<!-- <ion-item (click)="go_to_contact()" menuClose>
Contact Us
<!-- </ion-item> -->
</ion-content>
</ion-menu>
<!-- Disable swipe-to-go-back because it's poor UX to combine STGB with side menus -->
<ion-nav [root]="rootPage" #content swipeBackEnabled="true"></ion-nav>
app.module:-
import { BrowserModule } from '#angular/platform-browser';
import { ErrorHandler, NgModule } from '#angular/core';
import { IonicApp, IonicErrorHandler, IonicModule } from 'ionic-angular';
import { MyApp } from './app.component';
import { HomePage } from '../pages/home/home';
import { TabsPage } from '../pages/tabs/tabs';
import { AboutusPage } from '../pages/aboutus/aboutus';
import { ContactusPage } from '../pages/contactus/contactus';
import { CategoryPage } from '../pages/category/category';
import { ProductsByCategoryPage } from '../pages/products-by-category/products-by-category';
import { StatusBar } from '#ionic-native/status-bar';
import { SplashScreen } from '#ionic-native/splash-screen';
import { WooCommerceProvider } from '../providers/woocommerce/woocommerce';
import { HttpModule } from '#angular/http';
#NgModule({
declarations: [
MyApp,
HomePage,
TabsPage,
AboutusPage,
ContactusPage,
CategoryPage,
//ProductListPage,
ProductsByCategoryPage
],
imports: [
BrowserModule,
HttpModule,
IonicModule.forRoot(MyApp,{
mode:'ios'
}),
],
bootstrap: [IonicApp],
entryComponents: [
MyApp,
HomePage,
TabsPage,
AboutusPage,
ContactusPage,
CategoryPage,
ProductsByCategoryPage
],
providers: [
StatusBar,
SplashScreen,
{provide: ErrorHandler, useClass: IonicErrorHandler},
WooCommerceProvider
]
})
export class AppModule {}
Simply call the ChangeDetectorRef after successfull API call to refresh the changes in UI. PFB the sample code where we have triggered change detector on subscribe call. You can check the working version here
import { Component, ViewChild, ChangeDetectorRef } from '#angular/core';
import { NavController, Content } from 'ionic-angular';
#Component({
selector: 'page-home',
templateUrl: 'home.html'
})
export class HomePage {
#ViewChild(Content) content: Content;
Arr = Array; //Array type captured in a variable
num:number = 1000;
toolbar_color: string;
constructor(public navCtrl: NavController, public ref : ChangeDetectorRef) {
this.toolbar_color="secondary";
}
changeColor(){
this.toolbar_color="primary";
this.ref.detectChanges();
}
ionViewDidLoad() {
//this.content.enableJsScroll();
this.content.ionScrollEnd.subscribe(() => {
this.changeColor();
});
}
}
This is because your data is asynchronously loaded. The view has already been rendered by the time your data arrives.
One way to fix this is to add some kind of "refresh" method and call it when you receive the data (e.g., in .getAsync().then(...)).
I'm developing a mobile app using Ionic 2, Angularfire 2 and Firebase, but I'm stuck, this is my Firebase data structure:
I need to create a list from carrito, but at the same time I need to get the precio field and link it to another collection - precios, and get with the key value (as shown in the image above), the fields related (opcion & precio).
The code : list.ts
import { Component } from '#angular/core';
import { NavController, NavParams } from 'ionic-angular';
import {AngularFire, FirebaseListObservable} from 'angularfire2';
#Component({
selector: 'page-lista',
templateUrl: 'lista.html',
})
export class Lista {
public restaName:any;
serviceData: string;
carrito: FirebaseListObservable<any>;
precios: FirebaseListObservable<any>;
constructor(public navCtrl: NavController, public navParams:
NavParams, af: AngularFire, private shareService: ShareService) {
this.serviceData = shareService.getRestaName();
this.restaName = this.serviceData
this.carrito = af.database.list('/carrito', {
query: {
orderByChild: 'restaname',
equalTo: this.restaName
}
});
this.precios = af.database.list('/precios', {
query: {
orderByKey: true,
equalTo: this.precio ???? ---> HERE BEGIN MY DOUBTS
}
});
}
Here is part of lista.html
<ion-content padding>
<ion-list>
<ion-item *ngFor="let item of carrito | async ">
<p> {{item.prodname}} - {{item.cantidad}}</p>
</ion-item>
<ion-item *ngFor="let precio of precios | async "> ??? HOW CAN I GET THE FIELDS precio and opcion
<p>${{precio.precio}}</p>
</ion-item>
</ion-list>
</ion-content>
Any tips or comments will be appreciated !
You could use an Array of FirebaseObjectObservable instead of
precios: FirebaseListObservable<any>;
public precios :Array<FirebaseObjectObservable<any>>
this.carrito.subscribe(carrito => carrito.forEach(singleCarrito=>
precios.push(af.database.object('/precios/'+singleCarrito.precio))