====
* Step 1 - Creating project
ng new TodoProject
* Step 1' - Creating project
ng serve
* Step 2 - Generating Welcome Component with ng generate
ng generate component welcome
* Step 3 - Generating and Setting up Login Component
ng generate component login
* Step 4 - Draw basic form to login
in app-component.html
in login.component.html
User name:
Password:
in login.component.ts
username = "ayoub";
password= "";
handleClick(){
console.log(this.username);
}
==========
* Step 5 - Using ngModel with 2 Way Data Binding in Login Page
in login.component.html
User name:
Password:
in app.module.ts
import { FormsModule } from '@angular/forms';
imports: [
BrowserModule,
AppRoutingModule,
FormsModule
],
==========
* Step 6 - Adding Hardcoded Authentication to Logic Component - ngIf directive
in login.component.html:
{{errorMessage}}
==========
* Step 12 - Best Practice - Create a Todo Class
list-todos.component.ts:
// put this new Todo class above or under class ListTodosComponent
export class Todo{
constructor(
public id: number,
public description: string,
public done: boolean,
public targetDate: Date
)
{
}
}
todos = [
new Todo(1, 'Learn to cook', false, new Date()),
new Todo(2, 'Become an expert at angular', false, new Date()),
new Todo(3, 'Visit family', false, new Date())
]
list-todos.component.html: add date and transform it through pipes
My Todo's
Description
Target Date
Is Completed?
{{todo.description}}
{{todo.targetDate | date | uppercase}}
{{todo.done}}
==========
* Step 13 - Adding Bootstrap Framework and Creating Components for Menu and Footer
styles.css:
@import url(https://unpkg.com/bootstrap@4.1.0/dist/css/bootstrap.min.css)
ng g c menu
ng g c footer
// html of menu and footer
menu.component.html:
TOP MENU ELEMENTS
footer.component.html:
FOOTER
app.component.html:
==========
* Step 14 - Using Bootstrap to Create a Menu with Navigation Links
menu.component.html:
==========
* Step 15 - Styling Footer and Other Components with CSS and Bootstrap
footer.component.html:
footer.component.css:
.footer {
position: absolute;
bottom: 0;
width:100%;
height: 40px;
background-color: #222222;
}
app.component.html:
list-todos.component.html:
My Todo's
+ remove caption
put the
inside
login.component.html:
Login!
{{errorMessage}}
User name:
Password:
==========
* Step 16 - Creating an Independent Authentication Service Component
ng generate service hardcodedAuthentication
hardcoded-authentication.service.ts:
authenticate(username, password){
if (username==="ayoub" && password==="dummy"){
return true;
}
return false;
}
login.component.ts:
constructor(private router: Router,
private hardcodedAuthenticationService: HardcodedAuthenticationService)
{
}
handleClick(){
if (this.hardcodedAuthenticationService.authenticate(this.username, this.password))
{
this.invalidLogin = false;
this.router.navigate(['welcome', this.username]);
}
else{
this.invalidLogin = true;
}
}
==========
* Step 17 - Using Session Storage to Store User Authentication Token
hardcoded-authentication.service.ts:
authenticate(username, password){
if (username==="ayoub" && password==="dummy"){
sessionStorage.setItem('authenticaterUser', username);
return true;
}
return false;
}
isUserLoggedIn() {
let user = sessionStorage.getItem('authenticaterUser')
return !(user === null)
}
==========
* Step 18 - Enabling Menu Links Based on User Authentication Token
menu.component.ts:
constructor(private hardcodedAuthenticationService
: HardcodedAuthenticationService) { }
menu.component.html: conditional display using *ngIf
==========
* Step 19 - Implementing Logout to remove User Authentication Token
ng generate component logout
const routes: Routes = [
{path:'', component:LoginComponent},
{path:'login', component:LoginComponent},
{path:'welcome/:name', component:WelcomeComponent},
{path:'todos', component:ListTodosComponent},
{path:'logout', component:LogoutComponent},
{path:'**', component:ErrorComponent}
];
logout.component.html:
You are logged out
Thank You For Using Our Application.
hardcoded-authentication.service.ts:
logout(){
sessionStorage.removeItem('authenticaterUser')
}
logout.component.ts
constructor(private hardcodedAuthenticationService: HardcodedAuthenticationService) { }
ngOnInit() {
this.hardcodedAuthenticationService.logout();
}
==========
* Step 20 - Securing Components using Route Guards - Part 1
// will ban access to urls like /todos directly (unless logged in)
ng generate service service/routeGuard
RouteGuardService implements CanActivate
// import { CanActivate } from '@angular/router';
RouteGuardService.ts:
constructor(private hardcodedAuthenticationService: HardcodedAuthenticationService) { }
canActivate(route: ActivatedRouteSnapshot, state: RouterStateSnapshot): boolean {
if (this.hardcodedAuthenticationService.isUserLoggedIn())
{
return true;
}
return false;
}
{path:'welcome/:name', component:WelcomeComponent, canActivate: [RouteGuardService]},
{path:'todos', component:ListTodosComponent, canActivate: [RouteGuardService]},
test access to /todos while not logged in
=> blank page
====================
// redirect /welcome and /todos to /login
route-guard.service.ts:
constructor(private hardcodedAuthenticationService: HardcodedAuthenticationService
, private router: Router) { }
-----------------------
canActivate(route: ActivatedRouteSnapshot, state: RouterStateSnapshot): boolean {
if (this.hardcodedAuthenticationService.isUserLoggedIn())
{
return true;
}
this.router.navigate(['login']);
--------------------------------
return false;
}
==========
* Step 21 - Connecting Angular Frontend with Todo List RESTful Service
ng generate service service/data/todoData
// don't forget to import HttpClientModule in App.module.ts to be able to use HttpClient
// import { HttpClientModule } from '@angular/common/http';
import { HttpClient } from '@angular/common/http';
todo-data.service.ts:
constructor(private http:HttpClient) { }
retrieveAllTodos(username) {
return this.http.get(`http://localhost:8080/users/${username}/todos`);
//console.log("Execute Hello World Bean Service")
}
list-todos.component.ts:
todos: Todo[];
// todos = [
// new Todo(1, 'Learn to cook', false, new Date()),
// new Todo(2, 'Become an expert at angular', false, new Date()),
// new Todo(3, 'Visit family', false, new Date())
// ]
constructor(private todoService:TodoDataService) { }
ngOnInit() {
this.todoService.retrieveAllTodos('ayoub').subscribe(
response => {
console.log(response);
this.todos = response;
}
)
}
test retrieving data, we have following error in FE console:
// Test the button click => Access to XMLHttpRequest at 'http://localhost:8080/hello-world-bean' from origin 'http://localhost:4200' has been blocked by CORS policy:
add to BE Controller:
@RestController
@CrossOrigin(origins="http://localhost:4200")
or
@CrossOrigin
public class TodoJpaController {
==========
* Step 22 - Adding Delete Todo Feature to Angular Frontend
list-todos.component.html:
REMARK: look well at message between `` and not "" to evaluate ${id}
// this.message = `Delete of Todo ${id} Successful!`;
=========
**********
==========
==========
* Step 23 - Creating Todo Component and Handle Routing
list-todos.component.html:
==========
* Step 25 - Creating Retrieve Todo Service and Connect Angular Frontend
getTodo() in java
todo-data.service.ts:
retrieveTodo(username, id){
return this.http.get(`http://localhost:8080/users/${username}/todos/${id}`);
}
todo.component.ts:
id:number
todo: Todo
constructor(
private todoService: TodoDataService,
private route: ActivatedRoute
) { }
ngOnInit() {
this.id = this.route.snapshot.params['id'];
this.todoService.retrieveTodo('ayoub', this.id)
.subscribe (
data => this.todo = data
)
}
see now update page: => partially working, with 2 errors
==========
* Step 26 - Improve Todo Page Appearance
todo.component.ts:
// first exception is because todo is null at first load
// This is first exception: ERROR TypeError: Cannot read property 'description' of undefined
ngOnInit() {
this.id = this.route.snapshot.params['id'];
this.todo = new Todo(1,'',false,new Date()); // <--
this.todoService.retrieveTodo('ayoub', this.id)
.subscribe (
data => this.todo = data
)
}
// ERROR 2: date is not being filled: with this msg:
// The specified value "2019-10-26T00:00:00.000+0000" does not conform to the required format, "yyyy-MM-dd".
todo.component.html:
==========
* Step 27 - Implementing Update Todo Feature in Angular Frontend
todo-data.service.ts:
updateTodo(username, id, todo){
return this.http.put(
`http://localhost:8080/users/${username}/todos/${id}`
, todo);
}
todo.component.ts:
constructor(
private todoService: TodoDataService,
private route: ActivatedRoute,
private router: Router
) { }
saveTodo() {
this.todoService.updateTodo('ayoub', this.id, this.todo)
.subscribe (
data => {
console.log(data)
this.router.navigate(['todos'])
}
)
}
==========
* Step 28 - Implementing New Todo Feature in Angular Frontend
list-todos.component.html:
list-todos.component.ts:
addTodo() {
this.router.navigate(['todos',-1])
}
todo.component.ts:
ngOnInit() {
this.id = this.route.snapshot.params['id'];
// this.todo = new Todo(1,'',false,new Date());
this.todo = new Todo(this.id,'',false,new Date());
if(this.id!=-1) {
this.todoService.retrieveTodo('ayoub', this.id)
.subscribe (
data => this.todo = data
)
}
}
// update this method
saveTodo() {
if(this.id == -1) {
this.todoService.createTodo('ayoub', this.todo)
.subscribe (
data => {
console.log(data)
this.router.navigate(['todos'])
}
)
} else {
this.todoService.updateTodo('ayoub', this.id, this.todo)
.subscribe (
data => {
console.log(data)
this.router.navigate(['todos'])
}
)
}
}
todo-data.service.ts
createTodo(username, todo){
return this.http.post(
`http://localhost:8080/users/${username}/todos`
, todo);
}
==========
* Step 29 - Improving Todo Form - Validation and Form Submit on Enter - ngSubmit
// 1- submit once clicked on enter
// 2- don't allow empty filed + length < 5
todo.component.html:
1- put the 2