Saving additional fields on sign-up in Firebase - firebase

We're trying to work out why our information is not sending to our DB, except for email. We want to save name, surname, etc. to Firebase, but it is only saving email. What are we doing wrong?
signup.ts:
import { Component } from '#angular/core';
import { SearchPage } from '../search/search';
import { MyBookingsPage } from '../my-bookings/my-bookings';
import { NavController, AlertController, LoadingController, Loading } from 'ionic-angular';
import { Auth, User, UserDetails, IDetailedError } from '#ionic/cloud-angular';
import { FormBuilder, FormGroup, Validators } from '#angular/forms';
import { AuthProvider } from '../../providers/auth/auth';
import { EmailValidator } from '../../validators/email';
#Component({
selector: 'page-signup',
templateUrl: 'signup.html'
})
export class SignupPage {
public signupForm:FormGroup;
public loading:Loading;
constructor(public navCtrl: NavController, public authProvider:AuthProvider, public formBuilder: FormBuilder, public user: User, public alertCtrl: AlertController, public loadingCtrl:LoadingController) {
this.signupForm = formBuilder.group({
name: ['', Validators.compose([Validators.required])],
surname: ['', Validators.compose([Validators.required])],
birthday: ['', Validators.compose([Validators.required])],
licenseNum: [''],
email: ['', Validators.compose([Validators.required, EmailValidator.isValid])],
password: ['', Validators.compose([Validators.minLength(6), Validators.required])]
});
}
signupUser(){
if (!this.signupForm.valid){
console.log(this.signupForm.value);
} else {
this.authProvider.signupUser(this.signupForm.value.name,
this.signupForm.value.surname,
this.signupForm.value.birthday,
this.signupForm.value.licenseNum,
this.signupForm.value.email,
this.signupForm.value.password)
.then(() => {
this.loading.dismiss().then( () => {
this.navCtrl.setRoot(MyBookingsPage);
});
}, (error) => {
this.loading.dismiss().then( () => {
let alert = this.alertCtrl.create({
message: error.message,
buttons: [
{
text: "Ok",
role: 'cancel'
}
]
});
alert.present();
});
});
this.loading = this.loadingCtrl.create();
this.loading.present();
}
}
}
auth.ts:
#Injectable()
export class AuthProvider {
public fireAuth:firebase.auth.Auth;
public userProfileRef:firebase.database.Reference;
constructor(public http: Http) {
this.fireAuth = firebase.auth();
this.userProfileRef = firebase.database().ref('/userProfile'); //linked to firebase node userProfile
console.log('Hello AuthProvider Provider');
}
signupUser(name: string, surname: string, birthday: any, licenseNum: string, email: string, password: string ): firebase.Promise<any> {
return this.fireAuth.createUserWithEmailAndPassword(email, password).then( newUser => {
this.userProfileRef.child(newUser.uid).set({
name: name,
surname: surname,
birthday: birthday,
licenseNum: licenseNum,
email: email,
password: password
});
});
}
}
This is the Firebase result.
We think that the problem is in signupUser in auth.ts, but we really don't know, and we can't find anything online that fits with our structure. If possible, we don't want to have to redo our entire project!
Thanks in advance!

You should use .update() function instead of .set() function to store information at firebase database.

Related

Ionic 4 & Firebase integration

So, I'm quite a noob when it comes to ionic 4 firebase integration. Basically I've managed to get the firebase authentication to work, but the problem is I can't seem to save the user's input in the sign up page to firebase database. I need it to work as I would like to link the user to his/her checklist.
This is my sign-up page.ts
import { Component, OnInit } from '#angular/core';
import { Router } from "#angular/router";
import { Platform, AlertController } from '#ionic/angular';
import { LoadingController, ToastController } from '#ionic/angular';
import { AngularFireAuth } from '#angular/fire/auth';
//disable side menu
import { MenuController } from '#ionic/angular';
#Component({
selector: 'app-signup',
templateUrl: './signup.page.html',
styleUrls: ['./signup.page.scss'],
})
export class SignupPage implements OnInit {
email: string = '';
password: string = '';
error: string = '';
username: string = '';
constructor(
private fireauth: AngularFireAuth,
public router: Router,
public menuCtrl: MenuController,
private toastController: ToastController,
private platform: Platform,
public loadingController: LoadingController,
public alertController: AlertController
) { }
async openLoader() {
const loading = await this.loadingController.create({
message: 'Please Wait ...',
duration: 2000
});
await loading.present();
}
async closeLoading() {
return await this.loadingController.dismiss();
}
signup() {
this.fireauth.auth.createUserWithEmailAndPassword(this.email, this.password)
.then(res => {
if (res.user) {
console.log(res.user);
this.updateProfile();
}
})
.catch(err => {
console.log(`login failed ${err}`);
this.error = err.message;
});
}
updateProfile() {
this.fireauth.auth.onAuthStateChanged((user) => {
if (user) {
console.log(user);
user.updateProfile({
displayName: this.username
})
.then(() => {
this.router.navigateByUrl('/login');
})
}
})
}
async presentToast(message, show_button, position, duration) {
const toast = await this.toastController.create({
message: message,
showCloseButton: show_button,
position: position,
duration: duration
});
toast.present();
}
ionViewWillEnter (){
this.menuCtrl.enable(false);
}
ngOnInit(){}
}
Actually, you aren't using the firebase database. The user.updateProfile method stores the displayName property in the Firebase Auth system. That information is saved in the Firebase Auth system.

In ionic how to set storage to login information so when restarting the app takes directly to the home page

I am using the ionic framework. How do I set storage to login information so if the app restart the user can go to the home page when filling the login information again and again.
import * as firebase from 'firebase/app';
import { Storage } from '#ionic/storage';
#Injectable({
providedIn: 'root'
})
export class AuthenticationService {
constructor(public storage: Storage) {}
loginUser(value){
firebase.auth().signInWithEmailAndPassword(value.email, value.password)
.then(() => {
console.log('Log In Successful, UID: ' + value.uid + 'Email: ' +
value.email);
this.storage.set('Email', value.email);
this.storage.set('Password', value.password);
})
}
}
Ref. My github Url
authentication.service.ts
import { Injectable } from '#angular/core';
import { Router } from '#angular/router';
import { Storage } from '#ionic/storage';
import { ToastController, Platform } from '#ionic/angular';
import { BehaviorSubject } from 'rxjs';
#Injectable({
providedIn: 'root'
})
export class AuthenticationService {
authState = new BehaviorSubject(false);
constructor(
private router: Router,
private storage: Storage,
private platform: Platform,
public toastController: ToastController
) {
this.platform.ready().then(() => {
this.ifLoggedIn();
});
}
ifLoggedIn() {
this.storage.get('USER_INFO').then((response) => {
if (response) {
this.authState.next(true);
}
});
}
login() {
var dummy_response = {
user_id: 'manzoor.alam#thinktac.com',
user_name: 'manzoor'
};
this.storage.set('USER_INFO', dummy_response).then((response) => {
this.router.navigate(['dashboard']);
this.authState.next(true);
});
}
logout() {
this.storage.remove('USER_INFO').then(() => {
this.router.navigate(['login']);
this.authState.next(false);
});
}
isAuthenticated() {
return this.authState.value;
}
}
In auth-guard.service.ts
import { Injectable } from '#angular/core';
import { AuthenticationService } from './authentication.service';
import { CanActivate } from '#angular/router';
#Injectable({
providedIn: 'root'
})
export class AuthGuardService implements CanActivate {
constructor( public authenticationService: AuthenticationService) { }
canActivate(): boolean {
return this.authenticationService.isAuthenticated();
}
}
App.component.ts file
import { Component } from '#angular/core';
import { Platform } from '#ionic/angular';
import { SplashScreen } from '#ionic-native/splash-screen/ngx';
import { StatusBar } from '#ionic-native/status-bar/ngx';
import { AuthenticationService } from './services/Authentication.service';
import { Router } from '#angular/router';
#Component({
selector: 'app-root',
templateUrl: 'app.component.html'
})
export class AppComponent {
constructor(
private platform: Platform,
private splashScreen: SplashScreen,
private statusBar: StatusBar,
private router: Router,
private authenticationService: AuthenticationService
) {
this.initializeApp();
}
initializeApp() {
this.platform.ready().then(() => {
this.statusBar.styleDefault();
this.splashScreen.hide();
this.authenticationService.authState.subscribe(state => {
if (state) {
this.router.navigate(['dashboard']);
} else {
this.router.navigate(['login']);
}
});
});
}
}
In app-routing.module.ts
import { NgModule } from '#angular/core';
import { PreloadAllModules, RouterModule, Routes } from '#angular/router';
import { AuthGuardService } from './services/auth-guard.service';
const routes: Routes = [
// { path: '', redirectTo: 'home', pathMatch: 'full' },
// { path: 'home', loadChildren: './home/home.module#HomePageModule' },
// { path: 'login', loadChildren: './login/login.module#LoginPageModule' },
// { path: 'dashboard', loadChildren: './dashboard/dashboard.module#DashboardPageModule' },
{ path: '', redirectTo: 'login', pathMatch: 'full' },
{ path: 'login', loadChildren: './login/login.module#LoginPageModule' },
{
path: 'dashboard',
loadChildren: './dashboard/dashboard.module#DashboardPageModule',
canActivate: [AuthGuardService]
// Here canActivate is a method inside the AuthGuardService which return boolen type values
}
];
#NgModule({
imports: [
RouterModule.forRoot(routes, { preloadingStrategy: PreloadAllModules })
],
exports: [RouterModule]
})
export class AppRoutingModule { }
Please Ref. My github url more details github Url
Use Router Guard.
A Guard is just an Angular service - or injectable - that controls the behavior of the router in a maintainable way. Let’s generate it with the CLI:
ionic generate guard guards/login
The guard contains a special canActivate method that we are required to implement that must return or resolve to a boolean value. Because Ionic Storage is Promise-based, we can just make it an async function. Its job is to read the loginComplete value from the device storage. If true it allows the route to active, but if false it will block the route and redirect to the login.
// ...omitted
import { Storage } from '#ionic/storage';
#Injectable({
providedIn: 'root'
})
export class LoginGuard implements CanActivate {
constructor(private storage: Storage, private router: Router) {}
async canActivate(
next: ActivatedRouteSnapshot,
state: RouterStateSnapshot
): Promise<boolean> {
const isComplete = await this.storage.get('loginComplete');
if (!isComplete) {
this.router.navigateByUrl('/login');
}
return isComplete;
}
}
Applying the Guard
app-routing.module
import { Routes, RouterModule } from '#angular/router';
import { LoginGuard } from './guards/login.guard';
const routes: Routes = [
{
path: '',
loadChildren: './tabs/tabs.module#TabsPageModule',
canActivate: [LoginGuard] // <-- apply here
},
{
path: 'login',
loadChildren: './login/login.module#LoginPageModule'
}
];
#NgModule(...)
export class AppRoutingModule {}
Login page
import * as firebase from 'firebase/app';
import { Storage } from '#ionic/storage';
#Injectable({
providedIn: 'root'
})
export class AuthenticationService {
constructor(public storage: Storage) {}
loginUser(value){
firebase.auth().signInWithEmailAndPassword(value.email, value.password)
.then(() => {
console.log('Log In Successful, UID: ' + value.uid + 'Email: ' +
value.email);
this.storage.set('Email', value.email);
this.storage.set('Password', value.password);
this.storage.set('loginComplete', true);
})
}
}
Hope it helps you :)
Ref url: AngularFirebase

Setting Firebase data to property in html file

Okay so i am fairly new at ionic and i am experiencing this problem where by i am getting the users data from firebase but whenever i set it to the public variable and try and reference it in the html file, i am getting a log error of "cannot set 'variable name' to property of undefined". Here is my code for a more clearer explanation and understanding of what i am trying to achieve. Thank you.
.ts file:
import { Component } from '#angular/core';
import { IonicPage, NavController, NavParams,AlertController,
LoadingController, Loading } from 'ionic-angular';
import {AngularFireAuth} from 'angularfire2/auth';
import { MenuPage } from '../menu/menu';
import firebase from 'firebase';
import { first } from 'rxjs/operators';
#IonicPage()
#Component({
selector: 'page-account',
templateUrl: 'account.html',
})
export class AccountPage {
public userinfo;
constructor(public navCtrl: NavController, public navParams: NavParams,
private alertCtrl:AlertController, public fAuth:AngularFireAuth,
public loading:LoadingController) {
}
ionViewDidLoad() {
console.log('ionViewDidLoad AccountPage');
this.readData();
}
isLoggedIn(){
return this.fAuth.authState.pipe(first()).toPromise();
}
userStatus(){
const user = this.isLoggedIn()
if(user){
console.log('logged in');
this.readData();
}else{
}
}
async readData(){
let load = this.loading.create({
content: "Setting up your profile...",
spinner:'dots'
});
load.present();
await this.fAuth.authState.subscribe((user:firebase.User) =>{
if(user){
firebase.database().ref('/users/' +
user.uid).once('value').then(function(snapshot){
if(snapshot.exists()){
var data = (snapshot.val() && snapshot.val().username) ||
'Anonymous';
//this.userinfo = data;
console.log(data);
}else{
console.log("i need a name");
}});
}else{
console.log("not logged in, log in please");
this.alertLogin();
};
});
console.log(this.userinfo );
load.dismiss();
}
getName(){
let alert = this.alertCtrl.create({
title: 'Hello new friend! :) please can you tell us your name...',
inputs: [
{
name: 'name',
placeholder: 'name'
}
],
buttons: [
{
text: 'Cancel',
role: 'cancel',
handler: data => {
console.log('Cancel clicked');
this.navCtrl.setRoot(MenuPage);
}
},
{
text: 'Confirm',
handler: data => {
this.fAuth.authState.subscribe((user:firebase.User) =>{
firebase.database().ref('/users/' + user.uid).set({
username:data.name
});
});
}
}
]
});
alert.present();
}
alertLogin(){
//if user is not already logged in
let alert = this.alertCtrl.create({
title: 'Whoa there Sally! you need to log in first! :)',
inputs: [
{
name: 'email',
placeholder: 'email'
},
{
name: 'password',
placeholder: 'Password',
type: 'password'
}
],
buttons: [
{
text: 'Cancel',
role: 'cancel',
handler: data => {
console.log('Cancel clicked');
this.navCtrl.setRoot(MenuPage);
}
},
{
text: 'Login',
handler: data => {
this.login(data.email,data.password);
}
},{
text: 'Register',
handler: data => {
this.register(data.email,data.password);
}
}
]
});
alert.present();
}
async login(email,password){
try{
var login = await this.fAuth.auth.signInWithEmailAndPassword(
email,
password
);
if(login){
console.log("Successfully logged in!");
}
}catch(err){
console.error(err);
alert("Sorry we couldnt find you in our system :(");
this.navCtrl.setRoot(MenuPage);
}
}
async register(email,password){
try{
var reg = await this.fAuth.auth.createUserWithEmailAndPassword(
email,
password
);
if(reg){
this.getName();
console.log("successfully registered!");
this.navCtrl.setRoot(AccountPage);
}
}catch(err){
console.error(err);
}
}
logout(){
this.fAuth.auth.signOut();
}
}
.html file:
<ion-item>
<h1>{{userinfo}}</h1>
</ion-item>
Okay so i have tried basically everything and have decided to rather just upload the name to the database and write it locally in the storage of the application. I will just pull the name, along with further details later on in the application process. However if anyone finds an answer for this post, i would greatly appreciate it!

Ionic 2: Unable to create table TypeError: Cannot read property 'apply' of undefined

I am trying to open a database and create a table in my Ionic 2 app.
The following method is part of a service and is supposed to open the db and create the table:
initDb() {
let db = new SQLite();
db.openDatabase({
name: "data.db",
location: "default"
}).then(() => {
db.executeSql("CREATE TABLE IF NOT EXISTS people (avatarUrl VARCHAR, firstName VARCHAR, lastName VARCHAR)", []).then((data) => {
console.log("Table created: ", data);
}, (error) => {
console.error("Unable to create table", error);
})
}, (error) => {
console.error("Unable to open database", error);
});
}
The method is called in my home page's constructor:
constructor(public platform: Platform, public navCtrl: NavController, public dbService: DBService) {
this.platform.ready().then(() => {
this.dbService.initDb();
});
}
I have no idea why I am getting this error (refer to the title).
Thanks
Sorry, I could not reproduce this error but build a testapp on my own. This app works with me, despite this is called within ready as well:
app.component.ts:
import { Component } from '#angular/core';
import { Platform } from 'ionic-angular';
import { StatusBar, Splashscreen, SQLite } from 'ionic-native';
import { TabsPage } from '../pages/tabs/tabs';
import { DbService } from '../providers/db-service';
#Component({
templateUrl: 'app.html',
providers: [DbService]
})
export class MyApp {
rootPage = TabsPage;
constructor(public platform: Platform, public dbService: DbService) {
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.
StatusBar.styleDefault();
Splashscreen.hide();
this.dbService.initDb();
});
}
}
I made this service by using this ionic-command:
ionic g provider DbService
db-service.ts:
import { Injectable } from '#angular/core';
import { Http } from '#angular/http';
import 'rxjs/add/operator/map';
import { SQLite } from 'ionic-native';
/*
Generated class for the DbService provider.
See https://angular.io/docs/ts/latest/guide/dependency-injection.html
for more info on providers and Angular 2 DI.
*/
#Injectable()
export class DbService {
constructor(public http: Http) {
console.log('Hello DbService Provider');
}
initDb() {
let db = new SQLite();
db.openDatabase({
name: "data.db",
location: "default"
}).then(() => {
db.executeSql("CREATE TABLE IF NOT EXISTS people (avatarUrl VARCHAR, firstName VARCHAR, lastName VARCHAR)", []).then((data) => {
console.log("Table created: ", data);
}, (error) => {
console.error("Unable to create table", error);
})
}, (error) => {
console.error("Unable to open database", error);
});
}
}
ionic-version: 2.1.18
cordova-version 6.0.0
Hope it helps.

NativeScript Route Set up for Firebase Login

I'm looking to set up firebase authentication on a NativeScript app and I'm having a hard time figuring out the best practice to set up the routes/components.
What I like to do is set it up like any typical modern app where if the user is not logged in then they are redirected to the login page. If there are logged in then they skip the login page and are redirected to their dashboard.
I have a user.service like this
import { Injectable } from '#angular/core';
import { RouterExtensions } from 'nativescript-angular/router';
import firebase = require("nativescript-plugin-firebase");
#Injectable()
export class UserService {
private uid;
private route;
constructor(router: RouterExtensions){
this.route = router;
}
public initFirebase(){ //This gets called from AppComponent Constructor
let that = this;
firebase.init({
onAuthStateChanged: function(data) {
if (data.loggedIn) {
that.route.navigate(["/dash"]);
} else {
console.log("NOT logged in.. redirecting to login");
that.route.navigate(["/login"]);
}
}
}).then(
(instance) => {
console.log("Firebase Initialized");
},
(error) => {
console.log("firebase.init error: " + error);
}
);
}
And in the router what I currently have set up is
export const routes = [
{ path: "", component: LoginComponent },
{ path: "dash", component: DashComponent},
{ path: "login", component: LoginComponent}
];
But that flashes the login page before it redirects to the dash which is terrible.
I also tried to do this..
export const routes = [
{ path: "", component: AppComponent },
{ path: "dash", component: DashComponent},
{ path: "login", component: LoginComponent},
];
But this for reason makes Firebase initialize twice.
SO finally I tried this..
export const routes = [
{ path: "", component: DashComponent},
{ path: "dash", component: DashComponent},
{ path: "login", component: LoginComponent},
];
But this runs the DashComponent constructor before I want it to.
I want firebase init in user.service run FIRST and then DashComponent run after the user service firebase init completes and redirects to dash.
What is the best practice to solve this?
You could use a guard service that validates if the user is logged in such as:
import { AuthGuardService } from "../../...."
export const routes = [
{ path: "", component: DashComponent},
{ path: "dash", component: DashComponent, canActivate:[AuthGuardService]},
{ path: "login", component: LoginComponent},
];
That will implement CanActive from "#angular/router".
There you can validate if a user is logged in through a service and redirect him to that.route.navigate(["/login"]); if he is not.
import { Injectable } from "#angular/core";
import { Observable } from 'rxjs/Observable';
import { CanActivate, RouterStateSnapshot, ActivatedRouteSnapshot } from "#angular/router";
import { RouterExtensions, PageRoute } from "nativescript-angular/router";
import { UserService } from "./user.service";
#Injectable()
export class AuthGuardService implements CanActivate {
private userService: UserService;
private router: RouterExtensions;
public constructor(userService: UserService,
router: RouterExtensions) {
this.router = router;
this.userService = userService;
}
public canActivate(route: ActivatedRouteSnapshot, state: RouterStateSnapshot): boolean {
if(!userService.IsAuthenticated()){
that.route.navigate(["/login"])
}
return this.userService.IsAuthenticated();
}
I know it's kinda late, but it might help someone.

Resources