Creating restricted members area in Angular Fire 2 - authentication

I am trying to make an application using angularfire 2. Can't find the perfect way to make the members area restricted that means only authenticated members can access that area. Here is my 'login.component.ts' file
import { Component, OnInit, HostBinding } from '#angular/core';
import { AngularFire, AuthProviders, AuthMethods } from 'angularfire2';
import { FormControl, FormGroup, Validators } from '#angular/forms';
import { Router } from '#angular/router';
#Component({
selector: 'app-login',
templateUrl: './login.component.html',
styleUrls: ['./login.component.css'],
})
export class LoginComponent {
state: string = '';
error: any;
login: FormGroup;
constructor(
public af: AngularFire,
private router: Router
) {
//official angfire 2 app example
//this.af.auth.subscribe(auth => console.log(auth));
}
ngOnInit() {
this.login = new FormGroup({
username: new FormControl('', Validators.required),
password: new FormControl('', Validators.required)
});
}
onSubmit() {
//console.log(this.login.value, this.login.valid);
var value = this.login.value;
//console.log(value.username);
//console.log(value.password);
this.af.auth.login({
email: value.username,
password: value.password,
},
{
provider: AuthProviders.Password,
method: AuthMethods.Password,
}).then(
(success) => {
console.log(success);
this.router.navigate(['/members']);
}).catch(
(err) => {
console.log(err);
this.error = err;
})
}
}
and the members.component.ts file
import { Component, OnInit } from '#angular/core';
import { AngularFire, AuthProviders, AuthMethods } from 'angularfire2';
import { Router } from '#angular/router';
#Component({
selector: 'app-other',
templateUrl: './members.component.html',
styleUrls: ['./members.component.css']
})
export class MembersComponent implements OnInit {
//name: "";
//state: string = '';
constructor(
public af: AngularFire,
private router: Router
) {
this.af.auth.subscribe(auth => {
if(auth) {
console.log(auth);
}
});
}
logout() {
this.af.auth.logout();
console.log('logged out');
this.router.navigate(['/login']);
}
ngOnInit() {
}
}
I know my code may be seem like a dumb one but actually I am trying to study over this. But there is not enough documentation to solve my problem I guess. Thanks in advance.

https://coursetro.com/posts/code/32/Create-a-Full-Angular-Authentication-System-with-Firebase
this is a great tutorial that solves your problem

Related

ExpressionChangedAfterItHasBeenCheckedError: Expression has changed after it was checked in HTTP loading interceptor

Goal:
Im trying to show a loading icon on every ajax call.To this end, I added an HTTP interceptor which sets a variable to true when one or more requests are ongoing and to false when all have completed. The UI tests for this value and shows a loader or not, depending.
Problem:
On every ajax call, an error is thrown:
ExpressionChangedAfterItHasBeenCheckedError:
Expression has changed after it was checked.
Previous value: 'ngIf: [object Object]'. Current value: 'ngIf: true'.
Simplified Stakckblitz with reproducible error:
https://stackblitz.com/edit/angular-h4rpfb
Code:
appcomponent.html:
<p *ngIf="loaderService.isLoading | async">
Loading!
</p>
<p *ngIf="!(loaderService.isLoading | async)">
Not Loading!
</p>
<button (click)="loadSomething()">Load Something</button>
{{matches|async}}
appcomponent.ts:
import { Component } from "#angular/core";
import { HttpClient } from "#angular/common/http";
import { LoaderService } from "./core";
import { Observable } from "rxjs";
#Component({
selector: "my-app",
templateUrl: "./app.component.html",
styleUrls: ["./app.component.css"]
})
export class AppComponent {
matches: Observable<any>;
constructor(public loaderService: LoaderService, private http: HttpClient) {}
loadSomething() {
this.matches = this.http.get("https://jsonplaceholder.typicode.com/posts");
}
}
loader.interceptor.ts:
import { Injectable } from '#angular/core';
import {
HttpErrorResponse,
HttpResponse,
HttpRequest,
HttpHandler,
HttpEvent,
HttpInterceptor
} from '#angular/common/http';
import { Observable } from 'rxjs/Observable';
import { LoaderService } from './loader.service';
#Injectable()
export class LoaderInterceptor implements HttpInterceptor {
private requests: HttpRequest<any>[] = [];
constructor(private loaderService: LoaderService) { }
removeRequest(req: HttpRequest<any>) {
const i = this.requests.indexOf(req);
if (i >= 0) {
this.requests.splice(i, 1);
}
console.log(i, this.requests.length);
this.loaderService.isLoading.next(this.requests.length > 0);
}
intercept(req: HttpRequest<any>, next: HttpHandler): Observable<HttpEvent<any>> {
this.requests.push(req);
this.loaderService.isLoading.next(true);
return Observable.create(observer => {
const subscription = next.handle(req)
.subscribe(
event => {
if (event instanceof HttpResponse) {
this.removeRequest(req);
observer.next(event);
}
},
err => { this.removeRequest(req); observer.error(err); },
() => { this.removeRequest(req); observer.complete(); });
// teardown logic in case of cancelled requests
return () => {
this.removeRequest(req);
subscription.unsubscribe();
};
});
}
}
loader.service.ts:
import { Injectable } from '#angular/core';
import { Observable } from 'rxjs/Observable';
import { ReplaySubject } from 'rxjs/ReplaySubject';
import { BehaviorSubject } from 'rxjs/BehaviorSubject';
#Injectable()
export class LoaderService {
public isLoading = new BehaviorSubject(false);
constructor() {}
}
Ok I got it to work by adding this to the component with the loader:
changeDetection: ChangeDetectionStrategy.OnPush
So the appcomponent.html now looks like this:
import { Component,ChangeDetectionStrategy } from "#angular/core";
import { HttpClient } from "#angular/common/http";
import { LoaderService } from "./core";
import { Observable } from "rxjs";
#Component({
changeDetection: ChangeDetectionStrategy.OnPush,
selector: "my-app",
templateUrl: "./app.component.html",
styleUrls: ["./app.component.css"]
})
export class AppComponent {
matches: Observable<any>;
constructor(public loaderService: LoaderService, private http: HttpClient) {}
loadSomething() {
this.matches = this.http.get("https://jsonplaceholder.typicode.com/posts");
}
}
Example:
https://stackblitz.com/edit/angular-n6fzjm

How to fix 'TypeError: this.form.get is not a function' in karma test runner

I am using formbuilder.group to create reactive form with the formcontrol name in ngOnInit() and made a get function for name, when I run ng test I get error as below
I have created the test case for my component using Simon Test extension
I tried importing ReactiveFormsModule, CommonModule in spec.ts
I tried changing form.get('name') to form.controls.name
Error in karma-test runner
Test1Component ngOnInit makes expected calls
TypeError: this.form.get is not a function
TypeError: this.form.get is not a function
at Test1Component.get [as name] (http://localhost:9877/_karma_webpack_/webpack:/src/app/test1/test1.component.ts:27:22)
at Test1Component../src/app/test1/test1.component.ts.Test1Component.printVal (http://localhost:9877/_karma_webpack_/webpack:/src/app/test1/test1.component.ts:23:22)
at Test1Component.SpyStrategy.exec (http://localhost:9877/absoluteC:/Users/ratnsing/Desktop/Ratnesh/Angular7/Xv1/node_modules/jasmine-core/lib/jasmine-core/jasmine.js?0b1eaf7a13cae32191eadea482cfc96ae41fc22b:5083:19)
at Test1Component.spy (http://localhost:9877/absoluteC:/Users/ratnsing/Desktop/Ratnesh/Angular7/Xv1/node_modules/jasmine-core/lib/jasmine-core/jasmine.js?0b1eaf7a13cae32191eadea482cfc96ae41fc22b:4873:44)
at Test1Component.<anonymous> (http://localhost:9877/absoluteC:/Users/ratnsing/Desktop/Ratnesh/Angular7/Xv1/node_modules/jasmine-core/lib/jasmine-core/jasmine.js?0b1eaf7a13cae32191eadea482cfc96ae41fc22b:4849:20)
at Test1Component.printVal (http://localhost:9877/absoluteC:/Users/ratnsing/Desktop/Ratnesh/Angular7/Xv1/node_modules/jasmine-core/lib/jasmine-core/jasmine.js?0b1eaf7a13cae32191eadea482cfc96ae41fc22b:4890:50)
at Test1Component../src/app/test1/test1.component.ts.Test1Component.ngOnInit (http://localhost:9877/_karma_webpack_/webpack:/src/app/test1/test1.component.ts:19:10)
at UserContext.<anonymous> (http://localhost:9877/_karma_webpack_/webpack:/src/app/test1/test1.component.spec.ts:28:17)
at ZoneDelegate../node_modules/zone.js/dist/zone.js.ZoneDelegate.invoke (http://localhost:9877/_karma_webpack_/webpack:/node_modules/zone.js/dist/zone.js:391:1)
at ProxyZoneSpec.push../node_modules/zone.js/dist/zone-testing.js.ProxyZoneSpec.onInvoke (http://localhost:9877/_karma_webpack_/webpack:/node_modules/zone.js/dist/zone-testing.js:289:1)
test1.component.ts
import { Component, OnInit } from '#angular/core';
import { FormGroup, FormBuilder } from '#angular/forms';
#Component({
selector: 'app-test1',
templateUrl: './test1.component.html',
styleUrls: ['./test1.component.css']
})
export class Test1Component implements OnInit {
form: FormGroup;
constructor(private formBuilder: FormBuilder) { }
ngOnInit() {
this.form = this.formBuilder.group({
name: ['Init Value']
});
this.printval();
}
printVal() {
console.log(this.name);
}
get name() {
return this.form.get('name');
}
}
test1.component.spec.ts
import { ComponentFixture, TestBed } from '#angular/core/testing';
import { NO_ERRORS_SCHEMA } from '#angular/core';
import { FormBuilder } from '#angular/forms';
import { Test1Component } from './test1.component';
describe('Test1Component', () => {
let component: Test1Component;
let fixture: ComponentFixture<Test1Component>;
beforeEach(() => {
const formBuilderStub = { group: object1 => ({}) };
TestBed.configureTestingModule({
schemas: [NO_ERRORS_SCHEMA],
declarations: [Test1Component],
providers: [{ provide: FormBuilder, useValue: formBuilderStub }]
});
fixture = TestBed.createComponent(Test1Component);
component = fixture.componentInstance;
});
it('can load instance', () => {
expect(component).toBeTruthy();
});
describe('ngOnInit', () => {
it('makes expected calls', () => {
const formBuilderStub: FormBuilder = fixture.debugElement.injector.get(
FormBuilder
);
spyOn(component, 'printVal').and.callThrough();
spyOn(formBuilderStub, 'group').and.callThrough();
component.ngOnInit();
expect(component.printVal).toHaveBeenCalled();
expect(formBuilderStub.group).toHaveBeenCalled();
});
});
});
I found that .get is a part of AbstractControl property,
expecting al the test cases to pass...
Can u try:
import { async, ComponentFixture, TestBed } from '#angular/core/testing';
import { ReactiveFormsModule, FormBuilder, FormsModule } from '#angular/forms';
import { CommonModule } from '#angular/common';
beforeEach(async(() => {
const formBuilderStub = { group: object1 => ({}) };
TestBed.configureTestingModule({
imports: [CommonModule,ReactiveFormsModule,FormsModule],
schemas: [NO_ERRORS_SCHEMA],
declarations: [Test1Component],
providers: [FormBuilder]
}).compileComponents();
fixture = TestBed.createComponent(Test1Component);
component = fixture.componentInstance;
}));
Remove overriding of FormBuilder service
providers: [{ provide: FormBuilder, useValue: formBuilderStub }]
Import ReactiveFormsModule in TestBed
Add .compileComponents();
Put it in async block

How to use the Capacitor Browser API

I am currently porting my project to Ionic 4 and wanted to replace the Cordova InAppBrowser with the Capacitor browser but with little success so far...
This is my page:
import { Component, OnInit } from '#angular/core';
import {Plugins} from '#capacitor/core';
const { Browser } = Plugins;
#Component({
selector: 'app-srd',
templateUrl: './srd.page.html',
styleUrls: ['./srd.page.scss'],
})
export class SrdPage implements OnInit {
constructor() {
}
async ngOnInit() {
const url = 'http://capacitor.ionicframework.com/';
await Browser.open({'url': url});
}
}
There is no console output and the page stays blank.
Any ideas what went wrong?
This should work.
Remove the quote around the first url:
import { Component, OnInit } from '#angular/core';
import {Plugins} from '#capacitor/core';
const { Browser } = Plugins;
#Component({
selector: 'app-srd',
templateUrl: './srd.page.html',
styleUrls: ['./srd.page.scss'],
})
export class SrdPage implements OnInit {
constructor() {
}
async ngOnInit() {
const url = 'http://capacitor.ionicframework.com/';
await Browser.open({'url': url});
}
}
import { Browser } from '#capacitor/browser';
async openLink(Url){
await Browser.open({ url: Url });
}
const url = 'http://capacitor.ionicframework.com/';
await Browser.open({url: url});

Unable to get data when making httpClient.get in angular 5

I am trying to do a http.get using httpclient. However, and i am getting
ReferenceError: data is not defined
Inside my component class when subscribing to service method.
import { Injectable } from '#angular/core';
import { HttpClient, HttpHeaders } from '#angular/common/http';
import { Observable } from 'rxjs/Observable';
const httpOptions = {
headers: new HttpHeaders()
.set('Authorization', 'Bearer xxxxx')
.set('Content-Type', 'application/json')
};
#Injectable()
export class SetsService {
constructor(private http: HttpClient) { }
getSet() {
return this.http.get('http://localhost:1234/api/users', httpOptions);
}
}
my component
import { Component, OnInit } from '#angular/core';
import { ActivatedRoute } from '#angular/router';
import { Router } from '#angular/router';
import { SetsService } from '../services/sets.service';
import { Observable } from 'rxjs/Observable';
#Component({
selector: 'app-sets',
templateUrl: './sets.component.html',
styleUrls: ['./sets.component.scss']
})
export class SetsComponent implements OnInit {
id: string = "";
set: any = {};
constructor(private route: ActivatedRoute, private router: Router, private _setsService: SetsService) {
this.route.params.subscribe(res => this.id = res.id);
}
ngOnInit() {
this.getSets();
}
getSets(){
this._setsService.getSet().subscribe(
(data) => { this.set = data },
err => console.error(err),
() => { console.log('done loading set') }
);
}}
When i look at the network the API call is successful and returning data.
Inside the html I am simply trying to print the set object.

The requested path contains undefined segment at index 0

authentication.service.ts in that my login service is define like this
import { Injectable } from '#angular/core';
import { Http, Headers, Response, RequestOptions } from '#angular/http';
import { Observable } from 'rxjs';
import 'rxjs/Rx';
import 'rxjs/add/operator/map'
import { AuthHttp } from 'angular2-jwt';
import { Router } from '#angular/router';
#Injectable()
export class AuthenticationService {
token: string;
redirectUrl: any;
constructor(public router: Router, private http: Http, private authHttp: AuthHttp) {
//set token if saved in local storage
if (localStorage.getItem('authToken') != null) {
try {
// var currentUser =
JSON.parse(localStorage.getItem('currentUser'));
this.token = localStorage.getItem('authToken');
// this.token = currentUser && currentUser.token;
} catch (e) {
localStorage.removeItem("authToken");
}
}
}
login(username: string, password: string) {
return this.http.post('http://localhost:3002/api/authenticate',({ username: username, password: password }))
.map(res => {
console.log(res);
var authToken = res.json().token;
localStorage.setItem('authToken', authToken);
let redirectUrlTemp: any;
redirectUrlTemp = this.redirectUrl;
this.redirectUrl = null;
if (!redirectUrlTemp) {
console.log(redirectUrlTemp);
redirectUrlTemp = ['/login'];
}
this.router.navigate(redirectUrlTemp);
},
err => {
//alert(error.text());
console.log(err.text());
});
}
logout(){
// clear token remove user from local storage to log user out
this.token = null;
localStorage.removeItem('authToken');
}
}
when i try to post data using postman it works properly but from angular 2 it not allowing to redirect from next page
Login.component.ts
import { Component, OnInit } from '#angular/core';
import { Router, ActivatedRoute } from '#angular/router';
import { AuthenticationService } from "app/services";
import { LoginRequest } from "app/models/models";
import { AlertService } from 'app/services';
import { Observable } from 'rxjs/Observable';
import 'rxjs/Rx';
import { Http, Response } from '#angular/http';
#Component({
moduleId: module.id,
selector: 'login',
templateUrl: 'login.component.html'
})
export class LoginComponent implements OnInit {
model: any = {};
getLogin: LoginRequest[] = [];
loading = false;
error = '';
returnUrl: string;
constructor(
private route: ActivatedRoute,
private router: Router,
private http: Http,
private alertService: AlertService,
private authenticationService: AuthenticationService) { }
login() {
this.loading = true;
this.authenticationService.login(this.model.username, this.model.password).subscribe(data => {
this.router.navigate([this.returnUrl]);
},
error => {
this.alertService.error(error);
this.loading = false;
});
//let redirect = this.authenticationService.redirectUrl ? this.authenticationService.redirectUrl : '/allTask';
}
}
auth.guadr.ts
import { Injectable } from '#angular/core';
import { Router, CanActivate, ActivatedRouteSnapshot, RouterStateSnapshot } from '#angular/router';
import { AuthenticationService } from "app/services";
#Injectable()
export class AuthGuard implements CanActivate {
constructor(private router: Router, private authService: AuthenticationService) { }
canActivate(route: ActivatedRouteSnapshot, state: RouterStateSnapshot): boolean {
if (localStorage.getItem('authToken')) {
// logged in so return true
return true;
}
this.authService.redirectUrl =[state.url];
this.router.navigate(['/login']);
return false;
}
}
This error means that navigate array parameter with index 0 is undefined.
In your case you didn't set this.returnUrl in Login.component.ts
this.router.navigate([this.returnUrl]);