Login, Registration Forms Added.
This commit is contained in:
parent
f8b7acd5c6
commit
2bca44ebe5
@ -1,20 +1,38 @@
|
|||||||
import { HttpClient } from '@angular/common/http';
|
import { HttpClient, HttpHeaders } from '@angular/common/http';
|
||||||
import { Injectable } from '@angular/core';
|
import { Injectable } from '@angular/core';
|
||||||
import { Router } from '@angular/router';
|
import { Router } from '@angular/router';
|
||||||
import { BehaviorSubject, map } from 'rxjs';
|
import { map, of, ReplaySubject } from 'rxjs';
|
||||||
import { environment } from 'src/environments/environment';
|
import { environment } from 'src/environments/environment';
|
||||||
import { IUser } from '../shared/models/user';
|
import { IUser } from '../shared/models/user';
|
||||||
|
|
||||||
@Injectable({
|
@Injectable({
|
||||||
providedIn: 'root'
|
providedIn: 'root'
|
||||||
})
|
})
|
||||||
export class AccoutService {
|
export class AccountService {
|
||||||
baseUrl = environment.apiUrl;
|
baseUrl = environment.apiUrl;
|
||||||
private currentUserSource = new BehaviorSubject<IUser>(null);
|
private currentUserSource = new ReplaySubject<IUser>(1);
|
||||||
currentUser$ = this.currentUserSource.asObservable();
|
currentUser$ = this.currentUserSource.asObservable();
|
||||||
|
|
||||||
constructor(private http: HttpClient, private router: Router) { }
|
constructor(private http: HttpClient, private router: Router) { }
|
||||||
|
|
||||||
|
loadCurrentUser(token: string){
|
||||||
|
if(token === null){
|
||||||
|
this.currentUserSource.next(null);
|
||||||
|
return of(null);
|
||||||
|
}
|
||||||
|
|
||||||
|
let headers = new HttpHeaders();
|
||||||
|
headers = headers.set('Authorization', `Bearer ${token}`);
|
||||||
|
return this.http.get(this.baseUrl + 'account', {headers}).pipe(
|
||||||
|
map((user: IUser) => {
|
||||||
|
if(user){
|
||||||
|
localStorage.setItem('token', user.token);
|
||||||
|
this.currentUserSource.next(user);
|
||||||
|
}
|
||||||
|
})
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
login(values: any){
|
login(values: any){
|
||||||
return this.http.post(this.baseUrl + 'account/login', values).pipe(
|
return this.http.post(this.baseUrl + 'account/login', values).pipe(
|
||||||
map((user: IUser) =>{
|
map((user: IUser) =>{
|
||||||
@ -31,6 +49,7 @@ export class AccoutService {
|
|||||||
map((user:IUser) => {
|
map((user:IUser) => {
|
||||||
if(user){
|
if(user){
|
||||||
localStorage.setItem('token', user.token);
|
localStorage.setItem('token', user.token);
|
||||||
|
this.currentUserSource.next(user);
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
);
|
);
|
||||||
@ -43,6 +62,6 @@ export class AccoutService {
|
|||||||
}
|
}
|
||||||
|
|
||||||
checkEmailExists(email: string){
|
checkEmailExists(email: string){
|
||||||
return this.http.get(this.baseUrl + '/account/emailexists?email=' + email);
|
return this.http.get(this.baseUrl + 'account/emailexists?email=' + email);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,17 +1,10 @@
|
|||||||
<div class="d-flex justify-content-center mt-5">
|
<div class="d-flex justify-content-center mt-5">
|
||||||
<div class="col-3">
|
<div class="col-3">
|
||||||
<form>
|
<form [formGroup]="loginForm" (ngSubmit)="onSubmit()">
|
||||||
<h1 class="h3 mb-3 fw-normal text-center">Login</h1>
|
<h1 class="h3 mb-3 fw-normal text-center">Login</h1>
|
||||||
|
<app-text-inputs formControlName="email" [label]="'Email Address'"></app-text-inputs>
|
||||||
<div class="form-floating mb-2">
|
<app-text-inputs formControlName="password" [label]="'Password'" [type]="'password'"></app-text-inputs>
|
||||||
<input type="email" class="form-control" id="floatingInput" placeholder="name@example.com">
|
<button [disabled]="loginForm.invalid" class="w-100 btn btn-lg btn-primary" type="submit">Sign in</button>
|
||||||
<label for="floatingInput">Email address</label>
|
|
||||||
</div>
|
|
||||||
<div class="form-floating mb-2">
|
|
||||||
<input type="password" class="form-control" id="floatingPassword" placeholder="Password">
|
|
||||||
<label for="floatingPassword">Password</label>
|
|
||||||
</div>
|
|
||||||
<button class="w-100 btn btn-lg btn-primary" type="submit">Sign in</button>
|
|
||||||
</form>
|
</form>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
@ -1,5 +1,7 @@
|
|||||||
import { Component, OnInit } from '@angular/core';
|
import { Component, OnInit } from '@angular/core';
|
||||||
import { FormControl, FormGroup, Validators } from '@angular/forms';
|
import { FormControl, FormGroup, Validators } from '@angular/forms';
|
||||||
|
import { ActivatedRoute, Router } from '@angular/router';
|
||||||
|
import { AccountService } from '../account.service';
|
||||||
|
|
||||||
@Component({
|
@Component({
|
||||||
selector: 'app-login',
|
selector: 'app-login',
|
||||||
@ -8,18 +10,30 @@ import { FormControl, FormGroup, Validators } from '@angular/forms';
|
|||||||
})
|
})
|
||||||
export class LoginComponent implements OnInit {
|
export class LoginComponent implements OnInit {
|
||||||
loginForm: FormGroup;
|
loginForm: FormGroup;
|
||||||
|
returnUrl: string;
|
||||||
|
|
||||||
|
|
||||||
constructor() { }
|
constructor(private accountService: AccountService, private router: Router, private activatedRoute: ActivatedRoute) { }
|
||||||
|
|
||||||
ngOnInit(): void {
|
ngOnInit(): void {
|
||||||
|
this.returnUrl = this.activatedRoute.snapshot.queryParams.returnUrl || '/shop';
|
||||||
|
this.createLoginForm();
|
||||||
}
|
}
|
||||||
|
|
||||||
createLoginForm(){
|
createLoginForm(){
|
||||||
this.loginForm = new FormGroup({
|
this.loginForm = new FormGroup({
|
||||||
email: new FormControl('', Validators.required),
|
email: new FormControl('', [Validators.required, Validators.pattern('^[\\w-\\.]+@([\\w-]+\\.)+[\\w-]{2,4}')]),
|
||||||
password: new FormControl('', Validators.required)
|
password: new FormControl('', Validators.required)
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
onSubmit(){
|
||||||
|
this.accountService.login(this.loginForm.value).subscribe({
|
||||||
|
next: () => { this.router.navigateByUrl(this.returnUrl); },
|
||||||
|
error: (e: any) => { console.log(e) },
|
||||||
|
complete: () => { console.log('complete')}
|
||||||
|
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -1 +1,17 @@
|
|||||||
<p>register works!</p>
|
<div class="d-flex justify-content-center mt-5">
|
||||||
|
<div class="col-3">
|
||||||
|
<form [formGroup]="registerForm" (ngSubmit)="onSubmit()">
|
||||||
|
<h1 class="h3 mb-3 fw-normal text-center">Register</h1>
|
||||||
|
<app-text-inputs formControlName="displayName" [label]="'Display Name'"></app-text-inputs>
|
||||||
|
<app-text-inputs formControlName="email" [label]="'Email Address'"></app-text-inputs>
|
||||||
|
<app-text-inputs formControlName="password" [label]="'Password'" [type]="'password'"></app-text-inputs>
|
||||||
|
<ul class="text-warning list-unstyled" *ngIf="errors">
|
||||||
|
<li *ngFor="let error of errors">
|
||||||
|
{{error}}
|
||||||
|
</li>
|
||||||
|
</ul>
|
||||||
|
<button [disabled]="registerForm.invalid" class="w-100 btn btn-lg btn-primary" type="submit">Register</button>
|
||||||
|
</form>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
@ -1,4 +1,8 @@
|
|||||||
import { Component, OnInit } from '@angular/core';
|
import { Component, OnInit } from '@angular/core';
|
||||||
|
import { AsyncValidatorFn, FormBuilder, FormGroup, Validators } from '@angular/forms';
|
||||||
|
import { Router } from '@angular/router';
|
||||||
|
import { map, of, switchMap, timer } from 'rxjs';
|
||||||
|
import { AccountService } from '../account.service';
|
||||||
|
|
||||||
@Component({
|
@Component({
|
||||||
selector: 'app-register',
|
selector: 'app-register',
|
||||||
@ -6,10 +10,52 @@ import { Component, OnInit } from '@angular/core';
|
|||||||
styleUrls: ['./register.component.scss']
|
styleUrls: ['./register.component.scss']
|
||||||
})
|
})
|
||||||
export class RegisterComponent implements OnInit {
|
export class RegisterComponent implements OnInit {
|
||||||
|
registerForm: FormGroup;
|
||||||
|
errors: string[];
|
||||||
|
|
||||||
constructor() { }
|
constructor(private fb: FormBuilder, private accountService: AccountService, private router: Router) { }
|
||||||
|
|
||||||
ngOnInit(): void {
|
ngOnInit(): void {
|
||||||
|
this.createRegisterForm();
|
||||||
|
}
|
||||||
|
|
||||||
|
createRegisterForm(){
|
||||||
|
this.registerForm = this.fb.group({
|
||||||
|
displayName: [null, [Validators.required]],
|
||||||
|
email: [null,
|
||||||
|
[Validators.required, Validators.pattern('^[\\w-\\.]+@([\\w-]+\\.)+[\\w-]{2,4}')],
|
||||||
|
[this.validateEmailNotTaken()]
|
||||||
|
],
|
||||||
|
password: [null, [Validators.required],]
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
onSubmit(){
|
||||||
|
this.accountService.register(this.registerForm.value).subscribe({
|
||||||
|
next: (response) => { this.router.navigateByUrl('/shop')},
|
||||||
|
error: (e: any) => {
|
||||||
|
console.log(e);
|
||||||
|
this.errors = e.errors;
|
||||||
|
},
|
||||||
|
complete: () => { console.log('completed') }
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
validateEmailNotTaken(): AsyncValidatorFn {
|
||||||
|
return control => {
|
||||||
|
return timer(500).pipe(
|
||||||
|
switchMap(() => {
|
||||||
|
if(!control.value){
|
||||||
|
return of(null);
|
||||||
|
}
|
||||||
|
return this.accountService.checkEmailExists(control.value).pipe(
|
||||||
|
map(res => {
|
||||||
|
return res ? {emailExists: true} : null;
|
||||||
|
})
|
||||||
|
);
|
||||||
|
})
|
||||||
|
);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -1,5 +1,6 @@
|
|||||||
import { NgModule } from '@angular/core';
|
import { NgModule } from '@angular/core';
|
||||||
import { RouterModule, Routes } from '@angular/router';
|
import { RouterModule, Routes } from '@angular/router';
|
||||||
|
import { AuthGuard } from './core/guards/auth.guard';
|
||||||
import { NotFoundComponent } from './core/not-found/not-found.component';
|
import { NotFoundComponent } from './core/not-found/not-found.component';
|
||||||
import { ServerErrorComponent } from './core/server-error/server-error.component';
|
import { ServerErrorComponent } from './core/server-error/server-error.component';
|
||||||
import { TestErrorComponent } from './core/test-error/test-error.component';
|
import { TestErrorComponent } from './core/test-error/test-error.component';
|
||||||
@ -12,7 +13,7 @@ const routes: Routes = [
|
|||||||
{path: 'not-found', component: NotFoundComponent, data: {breadcrumb: 'Not Found'}},
|
{path: 'not-found', component: NotFoundComponent, data: {breadcrumb: 'Not Found'}},
|
||||||
{path: 'shop', loadChildren: ()=> import('./shop/shop.module').then(mod => mod.ShopModule), data: {breadcrumb: 'Shop'}},
|
{path: 'shop', loadChildren: ()=> import('./shop/shop.module').then(mod => mod.ShopModule), data: {breadcrumb: 'Shop'}},
|
||||||
{path: 'basket', loadChildren: ()=> import('./basket/basket.module').then(mod => mod.BasketModule), data: {breadcrumb: 'Shopping Cart'}},
|
{path: 'basket', loadChildren: ()=> import('./basket/basket.module').then(mod => mod.BasketModule), data: {breadcrumb: 'Shopping Cart'}},
|
||||||
{path: 'checkout', loadChildren: ()=> import('./checkout/checkout.module').then(mod => mod.CheckoutModule), data: {breadcrumb: 'Checkout'}},
|
{path: 'checkout', canActivate: [AuthGuard], loadChildren: ()=> import('./checkout/checkout.module').then(mod => mod.CheckoutModule), data: {breadcrumb: 'Checkout'}},
|
||||||
{path: 'account', loadChildren: ()=> import('./account/account.module').then(mod => mod.AccountModule), data: {breadcrumb: {skip: true}}},
|
{path: 'account', loadChildren: ()=> import('./account/account.module').then(mod => mod.AccountModule), data: {breadcrumb: {skip: true}}},
|
||||||
{path: '**', redirectTo: 'not-found', pathMatch: 'full'}
|
{path: '**', redirectTo: 'not-found', pathMatch: 'full'}
|
||||||
];
|
];
|
||||||
|
@ -1,5 +1,6 @@
|
|||||||
import { Component, OnInit } from '@angular/core';
|
import { Component, OnInit } from '@angular/core';
|
||||||
import { BasketService } from './basket/basket.service';
|
import { BasketService } from './basket/basket.service';
|
||||||
|
import { AccountService } from './account/account.service';
|
||||||
|
|
||||||
@Component({
|
@Component({
|
||||||
selector: 'app-root',
|
selector: 'app-root',
|
||||||
@ -9,9 +10,23 @@ import { BasketService } from './basket/basket.service';
|
|||||||
export class AppComponent implements OnInit {
|
export class AppComponent implements OnInit {
|
||||||
title = 'SkiNet';
|
title = 'SkiNet';
|
||||||
|
|
||||||
constructor(private basketService: BasketService) {}
|
constructor(private basketService: BasketService, private accountService: AccountService) {}
|
||||||
|
|
||||||
ngOnInit(): void {
|
ngOnInit(): void {
|
||||||
|
this.loadBasket();
|
||||||
|
this.loadCurrentUser();
|
||||||
|
}
|
||||||
|
|
||||||
|
loadCurrentUser(){
|
||||||
|
const token = localStorage.getItem('token');
|
||||||
|
this.accountService.loadCurrentUser(token).subscribe({
|
||||||
|
next: () => { console.log('loader user') },
|
||||||
|
error: (e: any) => { console.log(e) },
|
||||||
|
complete: () => { console.log('completed') }
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
loadBasket(){
|
||||||
const basketId = localStorage.getItem('basket_id');
|
const basketId = localStorage.getItem('basket_id');
|
||||||
if(basketId){
|
if(basketId){
|
||||||
this.basketService.getBasket(basketId).subscribe({
|
this.basketService.getBasket(basketId).subscribe({
|
||||||
|
@ -8,6 +8,7 @@ import { ServerErrorComponent } from './server-error/server-error.component';
|
|||||||
import { ToastrModule } from 'ngx-toastr';
|
import { ToastrModule } from 'ngx-toastr';
|
||||||
import { SectionHeaderComponent } from './section-header/section-header.component';
|
import { SectionHeaderComponent } from './section-header/section-header.component';
|
||||||
import { BreadcrumbModule } from 'xng-breadcrumb';
|
import { BreadcrumbModule } from 'xng-breadcrumb';
|
||||||
|
import { SharedModule } from '../shared/shared.module';
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
@ -17,6 +18,7 @@ import { BreadcrumbModule } from 'xng-breadcrumb';
|
|||||||
CommonModule,
|
CommonModule,
|
||||||
RouterModule,
|
RouterModule,
|
||||||
BreadcrumbModule,
|
BreadcrumbModule,
|
||||||
|
SharedModule,
|
||||||
ToastrModule.forRoot({
|
ToastrModule.forRoot({
|
||||||
positionClass: 'toast-bottom-right',
|
positionClass: 'toast-bottom-right',
|
||||||
preventDuplicates: true
|
preventDuplicates: true
|
||||||
|
24
client/src/app/core/guards/auth.guard.ts
Normal file
24
client/src/app/core/guards/auth.guard.ts
Normal file
@ -0,0 +1,24 @@
|
|||||||
|
import { Injectable } from '@angular/core';
|
||||||
|
import { ActivatedRouteSnapshot, CanActivate, Router, RouterStateSnapshot, UrlTree } from '@angular/router';
|
||||||
|
import { map, Observable } from 'rxjs';
|
||||||
|
import { AccountService } from 'src/app/account/account.service';
|
||||||
|
|
||||||
|
@Injectable({
|
||||||
|
providedIn: 'root'
|
||||||
|
})
|
||||||
|
export class AuthGuard implements CanActivate {
|
||||||
|
constructor(private accountService: AccountService, private router: Router) {}
|
||||||
|
|
||||||
|
canActivate(
|
||||||
|
route: ActivatedRouteSnapshot,
|
||||||
|
state: RouterStateSnapshot): Observable<boolean> {
|
||||||
|
return this.accountService.currentUser$.pipe(
|
||||||
|
map(auth => {
|
||||||
|
if(auth){
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
this.router.navigate(['account/login'], {queryParams: {returnUrl: state.url}});
|
||||||
|
})
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
@ -8,7 +8,10 @@ export class LoadingInterceptor implements HttpInterceptor {
|
|||||||
constructor(private busyService: BusyService) {}
|
constructor(private busyService: BusyService) {}
|
||||||
|
|
||||||
intercept(req: HttpRequest<any>, next: HttpHandler): Observable<HttpEvent<any>> {
|
intercept(req: HttpRequest<any>, next: HttpHandler): Observable<HttpEvent<any>> {
|
||||||
|
if(!req.url.includes('emailexists')){
|
||||||
this.busyService.busy();
|
this.busyService.busy();
|
||||||
|
}
|
||||||
|
|
||||||
return next.handle(req).pipe(
|
return next.handle(req).pipe(
|
||||||
delay(1000),
|
delay(1000),
|
||||||
finalize(()=> {
|
finalize(()=> {
|
||||||
|
@ -10,8 +10,29 @@
|
|||||||
<i class="fa fa-shopping-cart fa-2x me-3 text-dark"></i>
|
<i class="fa fa-shopping-cart fa-2x me-3 text-dark"></i>
|
||||||
<div *ngIf="(basket$ | async) as basket" class="cart-no">{{basket.items.length}}</div>
|
<div *ngIf="(basket$ | async) as basket" class="cart-no">{{basket.items.length}}</div>
|
||||||
</a>
|
</a>
|
||||||
<a routerLink="/account/login" class="btn btn-outline-secondary me-3" href="#">Login</a>
|
<ng-container *ngIf="(currentUser$ | async) === null">
|
||||||
|
<a routerLink="/account/login" class="btn btn-outline-secondary ms-3 me-3" href="#">Login</a>
|
||||||
<a routerLink="/account/register" class="btn btn-outline-secondary me-3" href="#">Sign up</a>
|
<a routerLink="/account/register" class="btn btn-outline-secondary me-3" href="#">Sign up</a>
|
||||||
|
</ng-container>
|
||||||
|
<ng-container *ngIf="(currentUser$ | async) as user">
|
||||||
|
<div class="dropdown ms-3 me-5" dropdown>
|
||||||
|
<a class="dropdown-toggle" style="cursor: pointer" dropdownToggle>
|
||||||
|
<strong>Welcome {{(user.displayName)}}</strong>
|
||||||
|
</a>
|
||||||
|
<div class="dropdown-menu dropdown-menu-right" style="cursor: pointer" *dropdownMenu>
|
||||||
|
<a routerLink="/basket" class="dropdown-item d-flex align-items-center py-2">
|
||||||
|
<i class="fa fa-shopping-cart me-3"></i> View Basket
|
||||||
|
</a>
|
||||||
|
<a routerLink="/orders" class="dropdown-item d-flex align-items-center py-2">
|
||||||
|
<i class="fa fa-history me-3"></i> View Orders
|
||||||
|
</a>
|
||||||
|
<div class="dropdown-divider"></div>
|
||||||
|
<a (click)="logout()" class="dropdown-item d-flex align-items-center py-2">
|
||||||
|
<i class="fa fa-sign-out me-3"></i> Logout
|
||||||
|
</a>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</ng-container>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
</div>
|
</div>
|
||||||
|
@ -1,7 +1,9 @@
|
|||||||
import { Component, OnInit } from '@angular/core';
|
import { Component, OnInit } from '@angular/core';
|
||||||
import { Observable } from 'rxjs';
|
import { Observable } from 'rxjs';
|
||||||
|
import { AccountService } from 'src/app/account/account.service';
|
||||||
import { BasketService } from 'src/app/basket/basket.service';
|
import { BasketService } from 'src/app/basket/basket.service';
|
||||||
import { IBasket } from 'src/app/shared/models/baskset';
|
import { IBasket } from 'src/app/shared/models/baskset';
|
||||||
|
import { IUser } from 'src/app/shared/models/user';
|
||||||
|
|
||||||
@Component({
|
@Component({
|
||||||
selector: 'app-nav-bar',
|
selector: 'app-nav-bar',
|
||||||
@ -9,12 +11,18 @@ import { IBasket } from 'src/app/shared/models/baskset';
|
|||||||
styleUrls: ['./nav-bar.component.scss']
|
styleUrls: ['./nav-bar.component.scss']
|
||||||
})
|
})
|
||||||
export class NavBarComponent implements OnInit {
|
export class NavBarComponent implements OnInit {
|
||||||
basket$ : Observable<IBasket>
|
basket$ : Observable<IBasket>;
|
||||||
|
currentUser$: Observable<IUser>;
|
||||||
|
|
||||||
constructor(private basketService: BasketService) { }
|
constructor(private basketService: BasketService, private accountService: AccountService) { }
|
||||||
|
|
||||||
ngOnInit(): void {
|
ngOnInit(): void {
|
||||||
this.basket$ = this.basketService.basket$;
|
this.basket$ = this.basketService.basket$;
|
||||||
|
this.currentUser$ = this.accountService.currentUser$;
|
||||||
|
}
|
||||||
|
|
||||||
|
logout() {
|
||||||
|
this.accountService.logout();
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -0,0 +1,21 @@
|
|||||||
|
<div class="form-floating mb-2">
|
||||||
|
<input
|
||||||
|
[ngClass]="(controlDir && controlDir.control && controlDir.control.touched) ? !controlDir.control.valid ? 'is-invalid' : 'is-valid' : null"
|
||||||
|
[type]="type"
|
||||||
|
(input)="onChange($event.target.value)"
|
||||||
|
(blur)="onTouched()"
|
||||||
|
class="form-control"
|
||||||
|
id="{{label}}"
|
||||||
|
#input
|
||||||
|
placeholder="{{label}}"
|
||||||
|
>
|
||||||
|
<div *ngIf="controlDir && controlDir.control && controlDir.control.status === 'PENDING'" class="fa fa-spinner fa-spin loader"></div>
|
||||||
|
<label for="{{label}}">{{label}}</label>
|
||||||
|
<div class="text-warning" *ngIf="(controlDir && controlDir.control && !controlDir.control.valid && controlDir.control.touched)">
|
||||||
|
<span *ngIf="controlDir.control.errors?.required">{{label}} is required</span>
|
||||||
|
<span *ngIf="controlDir.control.errors?.pattern">Email is invalid</span>
|
||||||
|
</div>
|
||||||
|
<div class="text-warning d-block" *ngIf="(controlDir && controlDir.control && !controlDir.control.valid && controlDir.control.dirty)">
|
||||||
|
<span *ngIf="controlDir.control.errors?.emailExists">Email Address is in use.</span>
|
||||||
|
</div>
|
||||||
|
</div>
|
@ -0,0 +1,7 @@
|
|||||||
|
.loader {
|
||||||
|
position: absolute;
|
||||||
|
width: auto;
|
||||||
|
top: 20px;
|
||||||
|
right: 10px;
|
||||||
|
margin-top: 0;
|
||||||
|
}
|
@ -0,0 +1,40 @@
|
|||||||
|
import { Component, ElementRef, Input, OnInit, Self, ViewChild } from '@angular/core';
|
||||||
|
import { ControlValueAccessor, NgControl } from '@angular/forms';
|
||||||
|
|
||||||
|
@Component({
|
||||||
|
selector: 'app-text-inputs',
|
||||||
|
templateUrl: './text-inputs.component.html',
|
||||||
|
styleUrls: ['./text-inputs.component.scss']
|
||||||
|
})
|
||||||
|
export class TextInputsComponent implements OnInit, ControlValueAccessor {
|
||||||
|
@ViewChild('input', {static: true}) input: ElementRef;
|
||||||
|
@Input() type = 'text';
|
||||||
|
@Input() label: string;
|
||||||
|
|
||||||
|
constructor(@Self() public controlDir: NgControl) {
|
||||||
|
this.controlDir.valueAccessor = this;
|
||||||
|
}
|
||||||
|
|
||||||
|
ngOnInit(): void {
|
||||||
|
const control = this.controlDir.control;
|
||||||
|
const validators = control.validator ? [control.validator] : [];
|
||||||
|
const asyncValidators = control.asyncValidator ? [control.asyncValidator] : [];
|
||||||
|
|
||||||
|
control.setValidators(validators);
|
||||||
|
control.setAsyncValidators(asyncValidators);
|
||||||
|
control.updateValueAndValidity();
|
||||||
|
}
|
||||||
|
|
||||||
|
onChange(evt) {}
|
||||||
|
onTouched(evt?) {}
|
||||||
|
|
||||||
|
writeValue(obj: any): void {
|
||||||
|
this.input.nativeElement.value = obj || '';
|
||||||
|
}
|
||||||
|
registerOnChange(fn: any): void {
|
||||||
|
this.onChange = fn;
|
||||||
|
}
|
||||||
|
registerOnTouched(fn: any): void {
|
||||||
|
this.onTouched = fn;
|
||||||
|
}
|
||||||
|
}
|
@ -6,19 +6,22 @@ import { CarouselModule } from 'ngx-bootstrap/carousel';
|
|||||||
import { PagingHeaderComponent } from './components/paging-header/paging-header.component';
|
import { PagingHeaderComponent } from './components/paging-header/paging-header.component';
|
||||||
import { PagerComponent } from './components/pager/pager.component';
|
import { PagerComponent } from './components/pager/pager.component';
|
||||||
import { OrderTotalsComponent } from './components/order-totals/order-totals.component';
|
import { OrderTotalsComponent } from './components/order-totals/order-totals.component';
|
||||||
|
import { BsDropdownModule } from 'ngx-bootstrap/dropdown';
|
||||||
|
import { TextInputsComponent } from './components/text-inputs/text-inputs.component';
|
||||||
|
|
||||||
|
|
||||||
@NgModule({
|
@NgModule({
|
||||||
declarations: [
|
declarations: [
|
||||||
PagingHeaderComponent,
|
PagingHeaderComponent,
|
||||||
PagerComponent,
|
PagerComponent,
|
||||||
OrderTotalsComponent
|
OrderTotalsComponent,
|
||||||
|
TextInputsComponent
|
||||||
],
|
],
|
||||||
imports: [
|
imports: [
|
||||||
CommonModule,
|
CommonModule,
|
||||||
PaginationModule.forRoot(),
|
PaginationModule.forRoot(),
|
||||||
CarouselModule.forRoot(),
|
CarouselModule.forRoot(),
|
||||||
|
BsDropdownModule.forRoot(),
|
||||||
ReactiveFormsModule
|
ReactiveFormsModule
|
||||||
],
|
],
|
||||||
exports: [
|
exports: [
|
||||||
@ -27,7 +30,9 @@ import { OrderTotalsComponent } from './components/order-totals/order-totals.com
|
|||||||
PagerComponent,
|
PagerComponent,
|
||||||
CarouselModule,
|
CarouselModule,
|
||||||
OrderTotalsComponent,
|
OrderTotalsComponent,
|
||||||
ReactiveFormsModule
|
ReactiveFormsModule,
|
||||||
|
BsDropdownModule,
|
||||||
|
TextInputsComponent
|
||||||
]
|
]
|
||||||
})
|
})
|
||||||
export class SharedModule { }
|
export class SharedModule { }
|
||||||
|
Loading…
Reference in New Issue
Block a user