Ionic 2: Facebook Login -> Error: No Provider in NavController (TypeScript) - facebook

I've been working on the facebook login for my ionic 2 app
(used this tutorial: https://ionicthemes.com/tutorials/about/ionic2-facebook-login)
But now i get a weird error:
RunTimeError Error in :0:0 caused by: No provider for NavController
app.component.ts:
import { Component } from '#angular/core';
import { Platform } from 'ionic-angular';
import { StatusBar } from '#ionic-native/status-bar';
import { SplashScreen } from '#ionic-native/splash-screen';
import { NativeStorage } from '#ionic-native/native-storage';
import { TabsPage } from '../pages/tabs/tabs';
import { WelcomePage } from '../pages/welcome/welcome';
import { DetailPage } from '../pages/detail/detail';
#Component({
templateUrl: 'app.html'
})
export class MyApp {
rootPage: any = WelcomePage;
constructor(NativeStorage: NativeStorage, platform: Platform, statusBar: StatusBar, splashScreen: SplashScreen) {
platform.ready().then(() => {
// Here we will check if the user is already logged in
// because we don't want to ask users to log in each time they open the app
let env = this;
NativeStorage.getItem('user')
.then((data) => {
// user is previously logged and we have his data
// we will let him access the app
this.rootPage = DetailPage;
splashScreen.hide();
}, (error) => {
//we don't have the user data so we will ask him to log in
this.rootPage = WelcomePage;
splashScreen.hide();
});
statusBar.styleDefault();
});
}
}
welcome.ts:
import { Component } from '#angular/core';
import { Facebook, NativeStorage } from 'ionic-native';
import { NavController } from 'ionic-angular';
import { DetailPage } from '../detail/detail';
import { ViewChild } from '#angular/core';
#Component({
selector: 'page-welcome',
templateUrl: 'welcome.html'
})
export class WelcomePage {
rootPage: any = WelcomePage;
#ViewChild('navRoot') navCtrl: NavController;
FB_APP_ID: number = 123456789;
constructor() {
Facebook.browserInit(this.FB_APP_ID, "v2.8");
}
doFbLogin() {
let permissions = new Array();
let nav = this.navCtrl;
//the permissions your facebook app needs from the user
permissions = ["public_profile"];
Facebook.login(permissions)
.then(function (response) {
let userId = response.authResponse.userID;
let params = new Array();
//Getting name and gender properties
Facebook.api("/me?fields=name,gender", params)
.then(function (user) {
user.picture = "https://graph.facebook.com/" + userId + "/picture?type=large";
//now we have the users info, let's save it in the NativeStorage
NativeStorage.setItem('user',
{
name: user.name,
gender: user.gender,
picture: user.picture
})
.then(function () {
nav.push(DetailPage);
}, function (error) {
console.log(error);
})
})
}, function (error) {
console.log(error);
});
}
}

You cannot import NavController in app.component.ts or the root app page.
OPTION 1:
Try to get it using ViewChild
Give element id to root-nav
<ion-nav #navRoot [root]="rootPage"></ion-nav>
In component:
import {ViewChild} from '#angular/core';
#Component({
templateUrl: 'app.html'
})
export class MyApp {
rootPage: any = WelcomePage;
#ViewChild('navRoot') navCtrl:NavController;
constructor(nativeStorage: NativeStorage, platform: Platform, statusBar: StatusBar, splashScreen: SplashScreen) { //remove navcontroller injected
platform.ready().then(() => {
// Here we will check if the user is already logged in
// because we don't want to ask users to log in each time they open the app
let env = this;
//...
OPTION 2:
From your app.component.ts code, you dont actually need to import NavController at all if your html template only contains,
<ion-nav [root]="rootPage"></ion-nav>
Simply set the required page to rootPage.
nativeStorage.getItem('user')
.then( (data) => {
// user is previously logged and we have his data
// we will let him access the app
this.rootPage = DetailPage;
splashScreen.hide();
}, (error) => {
//we don't have the user data so we will ask him to log in
this.rootPage = WelcomePage;
splashScreen.hide();
});
Side Note: Better to use ()=>{} arrow functions for callbacks instead of saving context in second variable.

Related

Menu items not appearing programmatically ionic 3 when user signs in. (AWS Cognito)

I am building an ionic app using AWS as a backend (has been challenging!), and for some reason on my user sign-in page, I got this nasty bug that wasn't there when I was using firebase as the backend. In a nutshell, my side menu has items that should appear based on whether the user is logged in or not. If the user is logged in, the menu should have a logout item. If the user is not logged in, the menu should either not have any options, or a redundant sign-in option.
I got the hard part down, which was setting up AWS Cognito to work the sign-in logic, and setting the correct root page, however, after a user logs in, the menu does not show the logout option.
Funny thing, if I reload the app, the menu does show the logout option. Not sure why. Also weird, after I reload the app and I click the logout button, the correct options for a user that is not logged in do appear in the menu. If someone can take a look and tell me why the menu options only render correctly when I log out and if I log in only after I reload the app, I would be very grateful! Thank you in advance for your time! Code below...
app.component.ts:
import { Component } from '#angular/core';
import { Platform, NavController, MenuController } from 'ionic-angular';
import { StatusBar } from '#ionic-native/status-bar';
import { SplashScreen } from '#ionic-native/splash-screen';
import { TabsPage } from '../pages/tabs/tabs';
import { SignInPage } from '../pages/sign-in/sign-in';
import { AuthService } from '../services/auth';
#Component({
templateUrl: 'app.html'
})
export class MyApp {
rootPage: any;
isLoggedIn //this variable holds the status of the user and determines the menu items;
constructor(platform: Platform,
statusBar: StatusBar,
splashScreen: SplashScreen,
private menuCtrl: MenuController,
private authService: AuthService) {
this.verifyUserstate(); //method to check if a user is logged in
console.log(this.isLoggedIn); //debug line
console.log(this.menuCtrl.get()); //debug line
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();
});
}
onLoad(page: any) {
console.log("onLoad");
this.nav.setRoot(page);
this.menuCtrl.close();
}
onLogout() {
this.authService.logout();
this.verifyUserstate();
this.menuCtrl.close();
}
verifyUserstate() {
console.log("in verify userstate");
this.authService.isAuthenticated()
.then(() => {
this.isLoggedIn = true; //if a user is logged in = true
this.rootPage = TabsPage;
console.log(this.isLoggedIn); // more debug
})
.catch((error) => {
this.isLoggedIn = false; //if user is not logged in = false
this.rootPage = SignInPage;
console.log(this.isLoggedIn); //more debug
});
}
}
app.html:
<ion-menu [content]="nav">
<ion-header>
<ion-toolbar>
<ion-title>Menu</ion-title>
</ion-toolbar>
</ion-header>
<ion-content>
<ion-list>
<button ion-item icon-left (click)="onLoad(signinPage)" *ngIf="!isLoggedIn"> <!-- check isLoggin-->
<ion-icon name="log-in"></ion-icon>
Sign In
</button>
<button ion-item icon-left (click)="onLogout()" *ngIf="isLoggedIn">
<ion-icon name="log-out"></ion-icon>
Log Out
</button>
</ion-list>
</ion-content>
auth.ts:
import { Injectable } from "#angular/core";
import { AlertController } from "ionic-angular";
import { CognitoUserPool, AuthenticationDetails, CognitoUser, CognitoUserSession } from "amazon-cognito-identity-js";
const POOL_DATA = {
UserPoolId: "xx-xxxx-X_XXXX",
ClientId: "You do not need to know :)"
}
const userPool = new CognitoUserPool(POOL_DATA);
export class AuthService {
signin(email: string, password: string) {
let message: string;
var authenticationData = {
Username : email,
Password : password,
};
var authDetails = new AuthenticationDetails(authenticationData);
let userData = {
Username: email,
Pool: userPool
}
let cognitoUser = new CognitoUser(userData);
return new Promise((resolve, reject) => {
cognitoUser.authenticateUser(authDetails, {
onSuccess(result: CognitoUserSession) {
console.log(result)
resolve("Success!")
},
onFailure(error) {
let message: string = error.message;
reject(message);
}
}
logout() {
this.getAuthenticatedUser().signOut();
}
isAuthenticated() {
return new Promise((resolve, reject) => {
let user = this.getAuthenticatedUser();
if (user) {
user.getSession((err, session) => {
if(session.isValid()) {
resolve(true);
} else if (err) {
reject(err.message);
}
})
} else {
reject("Not authenticated");
}
});
}
}
Finally, the sign-in.ts file (where the magic of login in happens):
import { Component } from '#angular/core';
import { NgForm } from '#angular/forms';
import { LoadingController, AlertController } from 'ionic-angular';
import { AuthService } from '../../services/auth';
import { NavController } from 'ionic-angular/navigation/nav-controller';
import { MyApp } from '../../app/app.component';
#Component({
selector: 'page-sign-in',
templateUrl: 'sign-in.html',
})
export class SignInPage {
constructor(private authService: AuthService,
private loadingCtrl: LoadingController,
private alertCtrl: AlertController,
private navCtrl: NavController) {
}
onSignin(form: NgForm) {
const loading = this.loadingCtrl.create({
content: "Signing you in..."
});
loading.present();
this.authService.signin(form.value.email, form.value.password)
.then(data => {
this.navCtrl.setRoot(MyApp); /*navigate to myApp again to reverify the
*login status. This sets the right rootPage,
*but I have a feeling here also lies the menu problem.
*/
console.log(data);
})
.catch(error => {
console.log(error);
let alert = this.alertCtrl.create({
title: "Oops",
message: error,
buttons: ["Ok"]
});
alert.present();
})
loading.dismiss();
}
}

Ionic 3 OneSignal Push Notification Click Open Page

I use OneSignal Push Notification for Ionic 3 . I want to when click notification application open page.
My app.component.ts
import { Component, ViewChild } from '#angular/core';
import { Platform, NavController } from 'ionic-angular';
import { StatusBar } from '#ionic-native/status-bar';
import { SplashScreen } from '#ionic-native/splash-screen';
import { OneSignal } from '#ionic-native/onesignal';
import { DuyurularPage } from '../pages/duyurular/duyurular';
#Component({
templateUrl: 'app.html',
providers:[OneSignal],
template: '<ion-nav #myNav [root]="rootPage"></ion-nav>'
})
export class MyApp {
rootPage:any = 'MenuPage';
bgColor: string = '#fff';
#ViewChild('myNav') nav: NavController;
constructor(platform: Platform, statusBar: StatusBar, splashScreen:
SplashScreen, private oneSignal: OneSignal,) {
platform.ready().then(() => {
statusBar.styleDefault();
splashScreen.hide();
window["plugins"].OneSignal
.startInit("**************", "***********")
.handleNotificationOpened()
.handleNotificationReceived()
.endInit();
});
this.oneSignal.handleNotificationOpened().subscribe((jsonData) => {
alert(JSON.stringify(jsonData));
this.nav.push(DuyurularPage);
});
this.oneSignal.handleNotificationReceived().subscribe((jsonData) =>
{
alert(JSON.stringify(jsonData));
this.nav.push(DuyurularPage);
});
}
}
When I do mistake I don' t know. Notification coming but not show alert or not push DuyurularPage, just open homepage.
if you Need to Open a Specific page on Notification Tapped. Follow the technique.
In App.component.ts
this.oneSignal.handleNotificationOpened().subscribe((data) => {
// do something when a notification is opened
console.log('Tapped',data);
if(data.notification.payload.additionalData.landing_page != undefined && data.notification.payload.additionalData.landing_page != ''){
this.PushProvider.landing_page = data.notification.payload.additionalData.landing_page;
}
if(data.notification.payload.additionalData.product_id != undefined && data.notification.payload.additionalData.product_id != ''){
this.PushProvider.product_id = data.notification.payload.additionalData.product_id;
}
});
this.oneSignal.endInit();
//On Home Page
if(this.PushProvider.landing_page != undefined){
console.log('on home if',this.PushProvider.landing_page);
this.navCtrl.push('offerzonePage',{ from_tab: this.PushProvider.landing_page});
}
if(this.PushProvider.product_id != undefined){
console.log('on home if',this.PushProvider.product_id);
this.navCtrl.push('ProductPage',{ product_id: this.PushProvider.product_id });
}
On Pushprovicer.ts
import { Injectable } from '#angular/core';
import 'rxjs/add/operator/map';
import 'rxjs/add/operator/toPromise';
#Injectable()
export class PushProvider {
// Produc ID
product_id: any;
// Landing pages
landing_page: any;
}
can you use the below syntax and try;
import { Component, ViewChild } from '#angular/core';
import { Platform, NavController } from 'ionic-angular';
import { StatusBar } from '#ionic-native/status-bar';
import { SplashScreen } from '#ionic-native/splash-screen';
import { OneSignal } from '#ionic-native/onesignal';
import { DuyurularPage } from '../pages/duyurular/duyurular';
#Component({
templateUrl: 'app.html',
providers:[OneSignal],
template: '<ion-nav #myNav [root]="rootPage"></ion-nav>'
})
export class MyApp {
rootPage:any = 'MenuPage';
bgColor: string = '#fff';
#ViewChild('myNav') nav: NavController;
constructor(platform: Platform, statusBar: StatusBar, splashScreen:
SplashScreen, private oneSignal: OneSignal,) {
platform.ready().then(() => {
statusBar.styleDefault();
splashScreen.hide();
this.oneSignal.startInit('*****', '***');
this.oneSignal.inFocusDisplaying(this.oneSignal.OSInFocusDisplayOption.InAppAlert);
this.oneSignal.handleNotificationOpened().subscribe((jsonData) => {
alert(JSON.stringify(jsonData));
this.nav.push(DuyurularPage);
});
this.oneSignal.handleNotificationReceived().subscribe((jsonData) =>
{
alert(JSON.stringify(jsonData));
});
}
You cannot use NavController in app.component.ts it seems.
Can you use Nav or App
What I would do is create an obsevable and subscribe to it anywhere needed in my app. The observable will emit its next value whenever the plugin callback is fired.
RxJS Observable
Emit next value on callback
Subscribe anywhere in your app
Use provided NavCtrl to push a component into the view
The same principle would work if you inject ionic's Event.
Btw you have a random comma at the end of your constructor

passing parameter between pages ionic

Hi i´m new in ionic and I am trying to pass the scann information form one page to another, the thing its that when I execute the program I have a console.log to check if the info its passed correctly but on chrome console said undefined, letme paste my code:
home.ts where i try to send the info from the scan:
import { Component } from '#angular/core';
import { NavController,Platform } from 'ionic-angular';
import { BarcodeScanner } from '#ionic-native/barcode-scanner';
import { TabsPage } from '../tabs/tabs';
#Component({
selector: 'page-home',
templateUrl: 'home.html'
})
export class HomePage {
private barcodeText:String;
private barcodeFormat:String;
private platform:Platform;
private navController:NavController;
constructor(private barcodeScanner: BarcodeScanner,public navCtrl: NavController,platform:Platform) {
this.platform = platform;
this.navController = navCtrl;
}
doScan(){
console.log('scannig product barcode');
this.platform.ready().then(() => {
this.barcodeScanner.scan().then((result) => {
if (!result.cancelled) {
this.barcodeText = result.text;
this.scanningDone(this.barcodeText)
}
}, (error) => {
console.log('error when scanning product barcode');
});
});
}
scanningDone(data){
this.navController.push(TabsPage,{
data:data
});
}
main.ts where the info suppose to go:
import { Component } from '#angular/core';
import { NavController, NavParams , ToastController} from 'ionic-angular';
import { BarcodeScanner } from '#ionic-native/barcode-scanner';
import { DetailsPage } from '../details/details';
import { Http } from '#angular/http'
#Component({
selector: 'main',
templateUrl: 'main.html'
})
export class MainPage {
information: any[];
item:any;
private bcData;
constructor(public navCtrl: NavController, private http: Http,public params:NavParams) {
this.bcData = params.get('data');
console.log(params.get('data'));
let localData = http.get(this.bcData).map(res => res.json().items);
localData.subscribe(data => {
this.information = data;
})
}
on the console.log(params.get('data')); its where I get the undefinied on the console.
you could have a method in your TabsPage that handles opening and closing pages like this:
openPages(Page, Data){
this.navCtrl.push(Page,Data);
}
Then in your scanningDone Method:
scanningDone(data){
this.tabsPage.openPages(MainPage,{
data:data
});
}
How about using localStorage
look at this as well

Pause MyApp during modal.present()

Original Post:
I am coding an Ionic 2 Hybrid app and attempting to create a modal that logs into FB and gathers necessary information for the app to run properly.
While the modal is presented (and the user is logging in), I need the app to be paused in the background. In other words, it cannot be continuing with the subsequent processes until the modal is dismissed.
Here is the relevant portion of code as an example:
var user = firebase.auth().currentUser;
if (user) {
console.log("User is already signed in.");
} else {
console.log("No user is signed in.");
let profileModal = this.modalCtrl.create(ProfilePage);
profileModal.present();
}
console.log("test pause.")
While the modal is still being presented and before it is dismissed, "test pause." is being written to the console. I need it to NOT be written to the console until AFTER the modal is dismissed.
NOTE: I have everything working properly except this bit. I haven't figured out how to accomplish 'pausing' until the modal is dismissed.
Is there any way to do this?
Clarification:
I am presenting the modal in the ngOnInit() of the main app component. I am doing this because I need specific user information to be gathered before the main app component is loaded and any pages are set/added to the stack.
Otherwise, the rootpage will not be built properly.
Here is the updated code in its full context in the app.component.ts file:
import { Component, ViewChild, OnInit } from '#angular/core';
import { ModalController, Nav, Platform } from 'ionic-angular';
import { SettingsService } from './../services/settings';
import { StatusBar } from '#ionic-native/status-bar';
import { SplashScreen } from '#ionic-native/splash-screen';
import { HomePage } from './../pages/home/home';
import { SignInPage } from './../pages/signin/signin';
import { CreatePage } from './../pages/create/create';
import { ProfilePage } from './../modals/profile/profile';
import firebase from 'firebase';
#Component({
templateUrl: 'app.html'
})
export class MyApp implements OnInit {
#ViewChild(Nav) nav: Nav;
rootPage: any = HomePage;
homePage: any = HomePage;
signInPage: any = SignInPage;
createPage: any = CreatePage;
photoURL: string;
constructor(private modalCtrl: ModalController,
private platform: Platform,
private statusBar: StatusBar,
private splashScreen: SplashScreen,
private settingsService: SettingsService) {
this.initializeApp();
}
ngOnInit() {
var config = {
apiKey: "AIzaSyDmTh_LZuMPnn7nJRquoW5xWwgQ4Ia3J9E",
authDomain: "thevault-ba308.firebaseapp.com",
databaseURL: "https://thevault-ba308.firebaseio.com",
projectId: "thevault-ba308",
storageBucket: "thevault-ba308.appspot.com",
messagingSenderId: "1024205108979"
};
firebase.initializeApp(config);
var user = firebase.auth().currentUser;
if (user) {
console.log("User is already signed in.");
}
else {
console.log("No user is signed in.");
let profileModal = this.modalCtrl.create(ProfilePage);
profileModal.present();
profileModal.onDidDismiss(() => {
console.log("test pause.")
this.photoURL = this.settingsService.getUserPhoto();
console.log(this.settingsService.getUserName());
})
}
}
initializeApp() {
this.platform.ready().then(() => {
this.statusBar.styleDefault();
this.splashScreen.hide();
});
}
openPage(page) {
this.nav.setRoot(page);
}
signOut() {
firebase.auth().signOut().then((result) => {
console.log("Sign out success.");
this.nav.setRoot(SignInPage);
}).catch((error) => {
console.log(error.message);
});
}
}
You should move all the code that was supposed to execute after modal is dismissed in this modal.onDismiss() part. Like this:
let profileModal = this.modalCtrl.create(ProfilePage);
profileModal.present();
profileModal.onDismiss((data) => {
console.log("Data from modalPage :",data);
console.log("test pause."); // Here you go. The code will be paused till the modal is dismissed.
});
Moreover, you can pass data to the modalPage via navParams and retrieve from the modalPage as well using this.viewCtrl.dismiss(data);.
For more reference, look at this and this ionic 2 documentation.
I was able to resolve my problem by using *ngIf in the app.html file.
<ion-content *ngIf="photoURL != null">

ionic 2 check if user already logged in with angularfire2

I did facebook login to my app and I'm trying to check if the user logged in then go to HomePage,if not go to loginPage.
I did it with firebase but I'm trying to do that with angularfire2
that's my code with firebase (I want it in angularfire2)
firebase.auth().onAuthStateChanged((user) => {
var that=this;
if (user) {
if(this.reg_boolean=="true"){
console.log("regCompleted");
this.nav.setRoot(TabsPage,{
dep:this.department,year:this.year,semester:this.semester
})
this.rootPage=TabsPage;
}
else{
this.rootPage = SignupPage;
}
console.log("I'm here! HomePage");
} else {
this.rootPage = LoginPage;
console.log("I'm here! LoginPage");
}
});
I got this to work in app.component.ts file.
import { ViewChild } from '#angular/core';
import { Nav } from 'ionic-angular';
import { AngularFire } from 'angularfire2'; // import this, duh
import { HomePage } from '../pages/home/home';
import { LoginPage } from '../pages/login/login';
export class MyApp {
#ViewChild(Nav) nav: Nav;
rootPage: any;
pages: Array<{ title: string, component: any }>;
userName:string;
constructor(public platform: Platform,
public af: AngularFire,
public authService: AuthenticationService) { // used for logout
this.initializeApp();
// Listen for auth sub
af.auth.subscribe(user => {
this.rootPage = user ? HomePage : LoginPage;
});
....
So basically get listening on the subscribe and change the rootPage based on the value passed into the var user. You can do a console.log() on user if you want to be more specific with the redirection.