Before implementing authGuard in my project, everything was working fine. But, it seems authguard throwing an error.
I removed the authguard from the page and it was working. but then again added it back gave error.
App.routing.module.ts
{ path: 'login', loadChildren: './Users/login/login.module#LoginPageModule' },
{ path: 'students/:uName', loadChildren: './Academic/Students/students/students.module#StudentsPageModule',canActivate: [AuthGuard],},
{ path: 'registerclass', loadChildren: './Academic/Students/registerclass/registerclass.module#RegisterclassPageModule',canActivate: [AuthGuard], },
{ path: 'schedule', loadChildren: './Academic/Students/schedule/schedule.module#SchedulePageModule',canActivate: [AuthGuard], },
{ path: 'faculties', loadChildren: './Academic/Faculty/faculties/faculties.module#FacultiesPageModule',canActivate: [AuthGuard], },
{ path: 'addclass', loadChildren: './Academic/Faculty/addclass/addclass.module#AddclassPageModule',canActivate: [AuthGuard], },
auth.guard.ts
import { Injectable } from '#angular/core';
import { CanActivate,ActivatedRouteSnapshot, RouterStateSnapshot, UrlTree,Router } from '#angular/router';
import { Observable } from 'rxjs';
import * as firebase from 'firebase/app'
import 'firebase/auth'
#Injectable({
providedIn: 'root'
})
export class AuthGuard implements CanActivate {
constructor(private router: Router) {}
canActivate(
next: ActivatedRouteSnapshot,
state: RouterStateSnapshot
): boolean | Observable<boolean> | Promise<boolean> {
return new Promise((resolve, reject) => {
firebase.auth().onAuthStateChanged((user: firebase.User) => {
if (user) {
resolve(true);
} else {
console.log('User is not logged in');
this.router.navigate(['/login']);
resolve(false);
}
});
});
}
}// close of class Authguard
app.module.ts
import { NgModule } from '#angular/core';
import { BrowserModule } from '#angular/platform-browser';
import { RouteReuseStrategy } from '#angular/router';
import { IonicModule, IonicRouteStrategy } from '#ionic/angular';
import { SplashScreen } from '#ionic-native/splash-screen/ngx';
import { StatusBar } from '#ionic-native/status-bar/ngx';
import { AppComponent } from './app.component';
import { AppRoutingModule } from './app-routing.module';
import { AngularFireModule } from '#angular/fire'; //To initialize firebaseconfig
import { AngularFireAuthModule } from '#angular/fire/auth';
import { AngularFirestoreModule } from '#angular/fire/firestore';
var firebaseConfig = {
apiKey: "AIzaSyC7f8sjVR-cSeeee3ZbEErwOQReowwpTL0",
authDomain: "msuproject-74e5a.firebaseapp.com",
databaseURL: "https://msuproject-74e5a.firebaseio.com",
projectId: "msuproject-74e5a",
storageBucket: "msuproject-74e5a.appspot.com",
messagingSenderId: "748587348290",
appId: "1:748587348290:web:e10fe4336779cd2ee158db",
measurementId: "G-GE58MG9QF6"
};
#NgModule({
declarations: [AppComponent],
entryComponents: [],
imports: [
BrowserModule,
IonicModule.forRoot(),
AppRoutingModule,
AngularFireModule.initializeApp(firebaseConfig),
AngularFireAuthModule,
AngularFirestoreModule
],
providers: [
StatusBar,
SplashScreen,
{ provide: RouteReuseStrategy, useClass: IonicRouteStrategy }
],
bootstrap: [AppComponent]
})
export class AppModule {}
home.html
<ion-card style="text-align: center; background-color: rgb(19, 4, 4);">
<nav class="navCard">
<h1 class="h1Card">
<a [routerLink]="['/login']">Login</a> |
<a [routerLink]="['/faculties']">Faculty</a> |
Library |
Info
</h1>
</nav>
</ion-card>
So, when I click on "Faculty", It should take me to Faculty page rather than crashing the page.
First move the firebaseconfig object to another ts file, then inside the auth.guard.ts do the following:
import * as config from './config.ts';
let firebaseInit = firebase.initializeApp(config.firebaseConfig);
The other solution uses the firebase javascript SDK but since you are importing AngularFire you may as well use that.
auth.guard.ts
constructor(private router: Router,
private afAuth: AngularFireAuth,
private ngZone: NgZone) { }
canActivate(
next: ActivatedRouteSnapshot,
state: RouterStateSnapshot
): boolean | Observable<boolean> | Promise<boolean> {
return new Promise((resolve, reject) => {
this.afAuth.auth.onAuthStateChanged((user: firebase.User) => this.ngZone.run(() => {
if (user) {
resolve(true);
} else {
console.log('User is not logged in');
this.router.navigate(['/login']);
resolve(false);
}
});
});
}
Also I recommend moving your firebaseConfig into the environment file so you can have different ones for dev and production.
app.module.ts
import { environment } from '../environments/environment';
...
imports: [
...
AngularFireModule.initializeApp(environment.firebaseConfig),
...
Related
I'm running into an odd problem with my Ionic/angular app.
I'm using
"#angular/core": "~13.2.2"
"#capacitor/core": "3.4.0"
"#capacitor/ios": "3.4.0"
"#angular/fire": "^7.2.0"
"firebase": "^9.6.6",
It works well on the web-version and Android, but when I compile to iOS, I only get a blank screen. I've narrowed the problem down to the auth-guard
I have tried using
the #angular/fire/compat/authguard - blank screen
not using any guard - works fine
writing my own guard and always returning true - works fine
writing my own guard, code below - blank screen
Here are the app-routing.module.ts:
import { NgModule } from '#angular/core';
import { RouterModule, Routes } from '#angular/router';
import { AuthGuard } from '../guards/auth.guard';
import { AutoLoginGuard } from '../guards/auto-login.guard';
import { TabsPage } from './tabs.page';
const routes: Routes = [
{
path: '',
component: TabsPage,
children: [
{
path: '',
redirectTo: 'dashboard',
pathMatch: 'full',
},
{
path: 'dashboard',
loadChildren: () =>
import('../pages/dashboard/dashboard.module').then(
(m) => m.DashboardPageModule
),
canActivate: [AuthGuard],
},
{
path: 'welcome',
loadChildren: () =>
import('../pages/welcome/welcome.module').then(
(m) => m.WelcomePageModule
),
canActivate: [AutoLoginGuard],
},
{
path: 'login',
loadChildren: () =>
import('../pages/login/login.module').then((m) => m.LoginPageModule),
canActivate: [AutoLoginGuard],
},
],
},
];
#NgModule({
imports: [RouterModule.forChild(routes)],
})
export class TabsPageRoutingModule {}
and the auth.guard.ts
import { Injectable } from '#angular/core';
import { CanActivate, Router } from '#angular/router';
import { Auth, onAuthStateChanged } from '#angular/fire/auth';
#Injectable({
providedIn: 'root',
})
export class AuthGuard implements CanActivate {
constructor(private auth: Auth, private router: Router) {}
canActivate(): Promise<boolean> {
return new Promise(async (resolve, reject) => {
onAuthStateChanged(this.auth, async (user) => {
if (user) {
console.log('User authenticated');
resolve(true);
} else {
console.log('User redirected to login');
this.router.navigateByUrl('/', { replaceUrl: true });
reject(false);
}
});
});
}
}
Any idea what might be causing this issue?
Found the answer (or rather Simon Grimm did): it's a bug in the capacitor SDK.
When initializing the auth module you have to adjust for Capacitor:
app.module.ts:
import { Capacitor } from '#capacitor/core';
import { indexedDBLocalPersistence, initializeAuth } from 'firebase/auth';
import { getApp } from 'firebase/app';
...
imports: [ ...
provideAuth(() => {
if (Capacitor.isNativePlatform()) {
return initializeAuth(getApp(), {
persistence: indexedDBLocalPersistence,
});
} else {
return getAuth();
}
}),
...
]
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
I get the error
Uncaught (in promise): Error: No provider for AngularFire!
When I tried to call firebase.auth().onAuthStateChanged.
Don't know why this happens. Please help.
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 { HomePage } from '../pages/home/home';
import { Login } from '../pages/login/login';
import firebase from 'firebase';
#Component({
templateUrl: 'app.html'
})
export class MyApp {
rootPage:any = Login;
isAuthenticated = false;
constructor(platform: Platform, statusBar: StatusBar, splashScreen: SplashScreen) {
firebase.initializeApp({
apiKey: "AIzaSyC94rD8wXG0aRLTcG29qVGw8CFfvCK7XVQ",
authDomain: "myfirstfirebaseproject-6da6c.firebaseapp.com",
});
firebase.auth().onAuthStateChanged(user => {
if (user) {
this.isAuthenticated = true;
this.rootPage = HomePage;
} else {
this.isAuthenticated = false;
this.rootPage = Login;
}
});
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();
});
}
}
Your config isn't set up properly. You should have this code in your app.module.ts, not in your component.
import {
AngularFireModule,
AuthMethods,
AuthProviders
} from 'angularfire2';
...
#NgModule({
bootstrap: [AppComponent],
declarations: [AppComponent],
imports: [
AngularFireModule.initializeApp({
apiKey: '<some-key>',
authDomain: '<some-project-authdomain>',
databaseURL: '<some-database-URL>',
storageBucket: '<some-storage-bucket>'
}, {
method: AuthMethods.Password,
provider: AuthProviders.Password
}),
BrowserModule,
...
]
})
class AppModule {}
platformBrowserDynamic().bootstrapModule(AppModule);
This is where you should have the above code. If you don't have the provider set, you'll keep getting the error.
I am fairly new to Angular2 and I am having issues adding Dragula to my application. When I run the application an error is thrown prior to loading the home page:
Exception: Call to Node module failed with error: Prerendering failed because of error: ReferenceError: document is not defined
The error message mentions Prerending which I suspect is in relation to the project using asp-prerender-module.
I've tried to follow official tutorials from Dragula and forum posts. Below are my app.module and component file snippets (... denotes summarised code):
app.module.ts
import { NgModule } from '#angular/core';
import { RouterModule } from '#angular/router';
import { UniversalModule } from 'angular2-universal';
import { AppComponent } from './components/app/app.component'
...
import { SearchComponent } from './components/search/search.component';
import { BrowserModule } from '#angular/platform-browser';
import { CommonModule } from '#angular/common';
import { FormsModule } from '#angular/forms';
import { Injectable } from '#angular/core';
import { DragulaModule } from 'ng2-dragula';
#NgModule({
bootstrap: [ AppComponent ],
declarations: [
AppComponent,
...
SearchComponent
],
imports: [
UniversalModule,
BrowserModule,
FormsModule,
DragulaModule,
CommonModule,
RouterModule.forRoot([
{ path: '', redirectTo: 'home', pathMatch: 'full' },
...
{ path: 'search', component: SearchComponent },
{ path: '**', redirectTo: 'home' }
])
]
})
export class AppModule {
}
search.component.ts
import { Component } from '#angular/core';
import { Http } from '#angular/http';
import { SearchService } from '../../services/search.service';
import { DragulaService } from 'ng2-dragula';
#Component({
selector: 'search',
template: require('./search.component.html'),
providers: [SearchService, DragulaService]
})
I suspect I am missing an a step when including Dragula, but I cannot figure out where. I have included both dragula (^3.7.2) and ng2-dragula (^1.3.0) in my package.json file.
your DragulaService initialization is wrong!! check Dragula documentation link
search.component.ts
import { Component } from '#angular/core';
import { Http } from '#angular/http';
import { SearchService } from '../../services/search.service';
import { DragulaService } from 'ng2-dragula';
#Component({
selector: 'search',
template: require('./search.component.html'),
providers: [SearchService]
})
expoert searchcomponent{
constructor(private dragulaService: DragulaService) {
console.log('DragulaService created');
}
}
Now you can play with drag and drop
If you want more control over drag and drop you can add events and options to dragulaService.
constructor(private dragulaService: DragulaService) {
dragulaService.drag.subscribe((value) => {
console.log(`drag: ${value[0]}`);
this.onDrag(value.slice(1));
});
dragulaService.drop.subscribe((value) => {
console.log(`drop: ${value[0]}`);
this.onDrop(value.slice(1));
});
dragulaService.over.subscribe((value) => {
console.log(`over: ${value[0]}`);
this.onOver(value.slice(1));
});
dragulaService.out.subscribe((value) => {
console.log(`out: ${value[0]}`);
this.onOut(value.slice(1));
});
}
private onDrag(args) {
let [e, el] = args;
// do something
}
private onDrop(args) {
let [e, el] = args;
// do something
}
private onOver(args) {
let [e, el, container] = args;
// do something
}
private onOut(args) {
let [e, el, container] = args;
// do something
}
So, I'm currently trying to send a HTTP request, I'm doing everything exactly like in official guide and it's wont work (as usual when you make deal with Angular2)
Here is my app.module
import { NgModule } from '#angular/core';
import { BrowserModule } from '#angular/platform-browser';
import { RouterModule, Routes } from '#angular/router';
import { HttpModule, JsonpModule } from '#angular/http';
import { AppComponent } from './app.component';
import { PageComponent } from './modules/Affiliate/affiliate.component';
import { NotFoundComponent } from './not-found.component';
const routes: Routes =
[
{ path: 'page', component: PageComponent },
{ path: '404', component: NotFoundComponent },
{ path: '**', redirectTo: '404' }
];
#NgModule({
imports: [
BrowserModule,
RouterModule.forRoot(routes),
HttpModule,
JsonpModule
],
declarations: [
AppComponent,
],
bootstrap: [ AppComponent ]
})
export class AppModule { }
And here is my service, where I'm trying to send a http request
import { Injectable } from '#angular/core';
import { Headers, Http } from '#angular/http';
import 'rxjs/add/operator/toPromise';
#Injectable()
export class GridService {
constructor(private http: Http) { }
getTableRaws(url): Promise<any> {
return this.http.get(url)
.toPromise()
.then(response => response.json().data as any)
.catch(this.handleError);
}
private handleError(error: any): Promise<any> {
console.error('An error occurred', error);
return Promise.reject(error.message || error);
}
}
Any ideas, please
Following the docs, I guess you missed the data type for the url param:
getTableRaws(url: string): Promise<any> {
...
}
UPDATE:
You need to add GridService as a provider in app.module. Refer to this SO answer.
If you have made these changes then update your code in the question and also provide the contents of app.component here.
Here is the solution that works for me:
constructor(#Inject(Http) private http: Http) {}