diff --git a/src/app/app-routing.module.ts b/src/app/app-routing.module.ts index 7da2a6b..68a3bb1 100644 --- a/src/app/app-routing.module.ts +++ b/src/app/app-routing.module.ts @@ -6,6 +6,7 @@ import {CourseComponent} from './course/course.component'; import {courseResolver} from './services/course.resolver'; import {LoginComponent} from './login/login.component'; import {CreateCourseComponent} from './create-course/create-course.component'; +import { LoginReactiveComponent } from './login-reactive/login-reactive.component'; const routes: Routes = [ { @@ -30,7 +31,7 @@ const routes: Routes = [ }, { path: 'login', - component: LoginComponent + component: LoginReactiveComponent }, { path: '**', diff --git a/src/app/app.component.css b/src/app/app.component.css index 3516e92..fecf65e 100644 --- a/src/app/app.component.css +++ b/src/app/app.component.css @@ -1,5 +1,5 @@ ->>> body { +body { margin: 0; } diff --git a/src/app/app.module.ts b/src/app/app.module.ts index 8410579..538ec82 100644 --- a/src/app/app.module.ts +++ b/src/app/app.module.ts @@ -27,7 +27,7 @@ import { MatToolbarModule } from "@angular/material/toolbar"; import {CoursesService} from "./services/courses.service"; import { provideHttpClient, withInterceptorsFromDi } from "@angular/common/http"; import { CourseDialogComponent } from './course-dialog/course-dialog.component'; -import {FormsModule, ReactiveFormsModule} from '@angular/forms'; +import {FormGroup, FormsModule, ReactiveFormsModule} from '@angular/forms'; import {LoginComponent} from './login/login.component'; import { CreateCourseComponent } from './create-course/create-course.component'; import {MatNativeDateModule} from '@angular/material/core'; @@ -41,6 +41,8 @@ import {CreateCourseStep1Component} from './create-course/create-course-step-1/c import {FileUploadComponent} from './file-upload/file-upload.component'; import {MatProgressBarModule} from '@angular/material/progress-bar'; import {LoginReactiveComponent} from './login-reactive/login-reactive.component'; +import { PasswordStrengthDirective } from './directives/password-strength.directive'; +import { OnlyOneErrorPipe } from './pipes/only-one-error.pipe'; @NgModule({ declarations: [ AppComponent, @@ -56,7 +58,9 @@ import {LoginReactiveComponent} from './login-reactive/login-reactive.component' CreateCourseStep3Component, AddressFormComponent, FileUploadComponent, - LoginReactiveComponent + LoginReactiveComponent, + PasswordStrengthDirective, + OnlyOneErrorPipe ], bootstrap: [AppComponent], imports: [BrowserModule, BrowserAnimationsModule, diff --git a/src/app/create-course/create-course-step-1/create-course-step-1.component.html b/src/app/create-course/create-course-step-1/create-course-step-1.component.html index e69de29..fcfd83b 100644 --- a/src/app/create-course/create-course-step-1/create-course-step-1.component.html +++ b/src/app/create-course/create-course-step-1/create-course-step-1.component.html @@ -0,0 +1,13 @@ +
+ + + + + + + {{title.value.length}} / 60 + + + + +
diff --git a/src/app/create-course/create-course-step-1/create-course-step-1.component.ts b/src/app/create-course/create-course-step-1/create-course-step-1.component.ts index 42ecaad..6bdf364 100644 --- a/src/app/create-course/create-course-step-1/create-course-step-1.component.ts +++ b/src/app/create-course/create-course-step-1/create-course-step-1.component.ts @@ -1,18 +1,23 @@ -import {Component, OnInit} from '@angular/core'; -import {FormBuilder, FormGroup, Validators} from '@angular/forms'; -import {CoursesService} from '../../services/courses.service'; -import {Observable} from 'rxjs'; -import {filter} from 'rxjs/operators'; +import { Component, OnInit } from "@angular/core"; +import { FormBuilder, FormGroup, Validators } from "@angular/forms"; +import { CoursesService } from "../../services/courses.service"; +import { Observable } from "rxjs"; +import { filter } from "rxjs/operators"; @Component({ - selector: 'create-course-step-1', - templateUrl: './create-course-step-1.component.html', - styleUrls: ['./create-course-step-1.component.scss'] + selector: "create-course-step-1", + templateUrl: "./create-course-step-1.component.html", + styleUrls: ["./create-course-step-1.component.scss"], }) export class CreateCourseStep1Component implements OnInit { + form = this.fb.group({ + title: [ + "", + [Validators.required, Validators.minLength(5), Validators.maxLength(60)], + ], + }); - ngOnInit() { - - } + constructor(private fb: FormBuilder) {} + ngOnInit() {} } diff --git a/src/app/create-course/create-course.component.html b/src/app/create-course/create-course.component.html index 6bfb728..da414ff 100644 --- a/src/app/create-course/create-course.component.html +++ b/src/app/create-course/create-course.component.html @@ -1,8 +1,17 @@ -
-

Create New Course

-
+ + + course landing page details + +
+ +
+
+
+ diff --git a/src/app/directives/password-strength.directive.ts b/src/app/directives/password-strength.directive.ts new file mode 100644 index 0000000..12108ae --- /dev/null +++ b/src/app/directives/password-strength.directive.ts @@ -0,0 +1,21 @@ +import { Directive } from "@angular/core"; +import { AbstractControl, NG_VALIDATORS, ValidationErrors, Validator, Validators } from "@angular/forms"; +import { createPasswordStrengthValidator } from "../validators/password-strength.validator"; + + +@Directive({ + selector: '[passwordStrength]', + providers: [{ + provide: NG_VALIDATORS, + useExisting: PasswordStrengthDirective, + multi: true + }] + + +}) +export class PasswordStrengthDirective implements Validator { + + validate(control: AbstractControl): ValidationErrors | null{ + return createPasswordStrengthValidator()(control); + } +} diff --git a/src/app/login-reactive/login-reactive.component.css b/src/app/login-reactive/login-reactive.component.css index a780a9f..c3d8164 100644 --- a/src/app/login-reactive/login-reactive.component.css +++ b/src/app/login-reactive/login-reactive.component.css @@ -14,5 +14,10 @@ border-bottom: 1px solid grey; margin-bottom: 10px; } +.field-message { + color: red; /* Example styling */ + font-size: 12px; + margin-top: 5px; +} diff --git a/src/app/login-reactive/login-reactive.component.html b/src/app/login-reactive/login-reactive.component.html index 4e9b389..def85f8 100644 --- a/src/app/login-reactive/login-reactive.component.html +++ b/src/app/login-reactive/login-reactive.component.html @@ -1,27 +1,68 @@ Login (Reactive) - - +
+ {{ form.value | json }} +
+ +
+ {{ form.valid | json }} +
diff --git a/src/app/login-reactive/login-reactive.component.ts b/src/app/login-reactive/login-reactive.component.ts index c73b78a..651c3df 100644 --- a/src/app/login-reactive/login-reactive.component.ts +++ b/src/app/login-reactive/login-reactive.component.ts @@ -1,21 +1,54 @@ -import { Component, OnInit } from '@angular/core'; - +import { Component, OnInit } from "@angular/core"; +import { + FormBuilder, + FormControl, + FormGroup, + NonNullableFormBuilder, + Validators, +} from "@angular/forms"; +import { createPasswordStrengthValidator } from "../validators/password-strength.validator"; @Component({ - selector: 'login', - templateUrl: './login-reactive.component.html', - styleUrls: ['./login-reactive.component.css'] + selector: "login", + templateUrl: "./login-reactive.component.html", + styleUrls: ["./login-reactive.component.css"], }) export class LoginReactiveComponent implements OnInit { + form = this.fb.group({ + email: [ + "", + { + validators: [Validators.required, Validators.email], + updateOn: "blur", + }, + ], + password: [ + "", + [ + Validators.required, + Validators.minLength(8), + createPasswordStrengthValidator(), + ], + ], + }); + + constructor(private fb: NonNullableFormBuilder) {} + + ngOnInit() {} + + get email() { + return this.form.controls["email"]; + } - - constructor() { - - + get password() { + return this.form.controls["password"]; } - ngOnInit() { + login() {} - } + reset() { + this.form.reset(); + console.log(this.form.value); + } } diff --git a/src/app/login/login.component.css b/src/app/login/login.component.css index a780a9f..7756bdc 100644 --- a/src/app/login/login.component.css +++ b/src/app/login/login.component.css @@ -15,4 +15,10 @@ margin-bottom: 10px; } +.field-message { + color: red; /* Example styling */ + font-size: 12px; + margin-top: 5px; +} + diff --git a/src/app/login/login.component.html b/src/app/login/login.component.html index e4ed4db..c4104ae 100644 --- a/src/app/login/login.component.html +++ b/src/app/login/login.component.html @@ -1,27 +1,73 @@ - Login + Login (Template-Driven-Form) - - - diff --git a/src/app/login/login.component.ts b/src/app/login/login.component.ts index 84905e8..4fcade4 100644 --- a/src/app/login/login.component.ts +++ b/src/app/login/login.component.ts @@ -1,21 +1,26 @@ -import { Component, OnInit } from '@angular/core'; +import { Component, OnInit } from "@angular/core"; +import { NgForm } from "@angular/forms"; @Component({ - selector: 'login', - templateUrl: './login.component.html', - styleUrls: ['./login.component.css'] + selector: "login", + templateUrl: "./login.component.html", + styleUrls: ["./login.component.css"], }) export class LoginComponent implements OnInit { - - constructor() { - - + val = { + email: "hello@gmail.com", + password: "123456" } + constructor() {} - ngOnInit() { + ngOnInit() {} + login(loginForm: NgForm) { + console.log(loginForm.value, loginForm.valid); + console.log(this.val); } + } diff --git a/src/app/pipes/only-one-error.pipe.ts b/src/app/pipes/only-one-error.pipe.ts new file mode 100644 index 0000000..89d7e7c --- /dev/null +++ b/src/app/pipes/only-one-error.pipe.ts @@ -0,0 +1,22 @@ +import { Pipe, PipeTransform } from "@angular/core"; + +@Pipe({ + name: "onlyOneError", +}) +export class OnlyOneErrorPipe implements PipeTransform { + transform(allErrors: any, errorsPriority: string[]): any { + if (!allErrors) { + return null; + } + const onlyOneError: any = {}; + + for (let error of errorsPriority) { + if (allErrors[error]) { + onlyOneError[error] = allErrors[error]; + break; + } + } + + return onlyOneError; + } +} diff --git a/src/app/validators/password-strength.validator.ts b/src/app/validators/password-strength.validator.ts new file mode 100644 index 0000000..5f9175e --- /dev/null +++ b/src/app/validators/password-strength.validator.ts @@ -0,0 +1,28 @@ +import { AbstractControl, ValidationErrors, ValidatorFn } from "@angular/forms"; + +export function createPasswordStrengthValidator(): ValidatorFn { + return (control: AbstractControl) : ValidationErrors | null => { + + const value = control.value; + + if (!value) { + return null; + } + + const hasUpperCase = /[A-Z]+/.test(value); + + const hasLowerCase = /[a-z]+/.test(value); + + const hasNumeric = /[0-9]+/.test(value); + + const passwordValid = hasUpperCase && hasLowerCase && hasNumeric; + + return !passwordValid ? {passwordStrength: true} : null; + + + } + + } + + +