Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions angular.json
Original file line number Diff line number Diff line change
Expand Up @@ -94,5 +94,8 @@
}
}
}
},
"cli": {
"analytics": "5af61b5e-4086-4e04-814e-3157b06486a2"
}
}
10 changes: 9 additions & 1 deletion src/app/app-routing.module.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,15 @@
import { NgModule } from '@angular/core';
import { RouterModule, Routes } from '@angular/router';
import { ContactsListComponent } from './contacts-list/contacts-list.component';
import { NewContactComponent } from './new-contact/new-contact.component';
import { ViewContactComponent } from './view-contact/view-contact.component';

const routes: Routes = [];
const routes: Routes = [
{ path: 'contacts', component: ContactsListComponent },
{ path: 'contacts/new', component: NewContactComponent },
{ path: 'contacts/:id', component: ViewContactComponent },
{ path: '', redirectTo: '/contacts', pathMatch: 'full' }
];

@NgModule({
imports: [RouterModule.forRoot(routes)],
Expand Down
24 changes: 19 additions & 5 deletions src/app/app.component.css
Original file line number Diff line number Diff line change
@@ -1,9 +1,23 @@
:host {
.container {
display: flex;
height: 100vh;
}

.page {
flex: 1;
display: flex;
justify-content: center;
.sidebar {
width: 200px;

padding: 1rem;
box-sizing: border-box;
}

.sidebar ul {
list-style: none;
padding: 0;
margin: 0;
}

.content {
flex: 1;
padding: 1rem;
box-sizing: border-box;
}
19 changes: 15 additions & 4 deletions src/app/app.component.html
Original file line number Diff line number Diff line change
@@ -1,4 +1,15 @@
<app-menu></app-menu>
<div class="page">
<router-outlet></router-outlet>
</div>
<div class="container">
<aside class="sidebar">
<h2>Menu</h2>
<nav>
<ul>
<li><a routerLink="/contacts">Contacts list</a></li>
<li><a routerLink="/contacts/new">Add new contact</a></li>
</ul>
</nav>
</aside>

<main class="content">
<router-outlet></router-outlet>
</main>
</div>
15 changes: 10 additions & 5 deletions src/app/app.module.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,11 +3,16 @@ import { BrowserModule } from '@angular/platform-browser';

import { AppRoutingModule } from './app-routing.module';
import { AppComponent } from './app.component';
import { LayoutModule } from './layout/layout.module';
import { ContactsListComponent } from './contacts-list/contacts-list.component';
import { NewContactComponent } from './new-contact/new-contact.component';
import { ViewContactComponent } from './view-contact/view-contact.component';
import { RouterModule } from '@angular/router';
import { ReactiveFormsModule } from '@angular/forms';

@NgModule({
declarations: [AppComponent],
imports: [BrowserModule, AppRoutingModule, LayoutModule],
bootstrap: [AppComponent],
declarations: [AppComponent, ContactsListComponent, NewContactComponent, ViewContactComponent],
imports: [BrowserModule, AppRoutingModule, RouterModule, ReactiveFormsModule],
providers: [],
bootstrap: [AppComponent]
})
export class AppModule {}
export class AppModule { }
16 changes: 16 additions & 0 deletions src/app/contact.service.spec.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
import { TestBed } from '@angular/core/testing';

import { ContactService } from './contact.service';

describe('ContactService', () => {
let service: ContactService;

beforeEach(() => {
TestBed.configureTestingModule({});
service = TestBed.inject(ContactService);
});

it('should be created', () => {
expect(service).toBeTruthy();
});
});
29 changes: 29 additions & 0 deletions src/app/contact.service.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
import { Injectable } from '@angular/core';

export interface Contact {
id: number;
name: string;
email: string;
}

@Injectable({
providedIn: 'root'
})
export class ContactService {
private contacts: Contact[] = [
{ id: 1, name: 'Alice', email: 'alice@mail.com' },
{ id: 2, name: 'Bob', email: 'bob@mail.com' }
];

getContacts(): Contact[] {
return this.contacts;
}

getContactById(id: number): Contact | undefined {
return this.contacts.find(c => c.id === id);
}

addContact(contact: Contact): void {
this.contacts.push(contact);
}
}
Empty file.
8 changes: 8 additions & 0 deletions src/app/contacts-list/contacts-list.component.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
<h2>Contacts</h2>
<ul>
<li *ngFor="let contact of contacts">
<a [routerLink]="['/contacts', contact.id]">
{{ contact.name }} - {{ contact.email }}
</a>
</li>
</ul>
23 changes: 23 additions & 0 deletions src/app/contacts-list/contacts-list.component.spec.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
import { ComponentFixture, TestBed } from '@angular/core/testing';

import { ContactsListComponent } from './contacts-list.component';

describe('ContactsListComponent', () => {
let component: ContactsListComponent;
let fixture: ComponentFixture<ContactsListComponent>;

beforeEach(async () => {
await TestBed.configureTestingModule({
imports: [ContactsListComponent]
})
.compileComponents();

fixture = TestBed.createComponent(ContactsListComponent);
component = fixture.componentInstance;
fixture.detectChanges();
});

it('should create', () => {
expect(component).toBeTruthy();
});
});
18 changes: 18 additions & 0 deletions src/app/contacts-list/contacts-list.component.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
import { Component, OnInit } from '@angular/core';
import { ContactService, Contact } from '../contact.service';

@Component({
selector: 'app-contacts-list',
templateUrl: './contacts-list.component.html',
styleUrl: './contacts-list.component.css'
})
export class ContactsListComponent implements OnInit {
contacts: Contact[] = [];

constructor(private contactService: ContactService) { }

ngOnInit(): void {
this.contacts = this.contactService.getContacts();
}

}
Empty file.
20 changes: 20 additions & 0 deletions src/app/new-contact/new-contact.component.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
<h2>New Contact</h2>
<form [formGroup]="contactForm" (ngSubmit)="onSubmit()">
<label>
Name:
<input type="text" formControlName="name">
</label>
<div *ngIf="contactForm.get('name')?.invalid && contactForm.get('name')?.touched">
Name is required
</div>

<label>
Email:
<input type="email" formControlName="email">
</label>
<div *ngIf="contactForm.get('email')?.invalid && contactForm.get('email')?.touched">
Enter a valid email
</div>

<button type="submit" [disabled]="contactForm.invalid">Add Contact</button>
</form>
23 changes: 23 additions & 0 deletions src/app/new-contact/new-contact.component.spec.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
import { ComponentFixture, TestBed } from '@angular/core/testing';

import { NewContactComponent } from './new-contact.component';

describe('NewContactComponent', () => {
let component: NewContactComponent;
let fixture: ComponentFixture<NewContactComponent>;

beforeEach(async () => {
await TestBed.configureTestingModule({
imports: [NewContactComponent]
})
.compileComponents();

fixture = TestBed.createComponent(NewContactComponent);
component = fixture.componentInstance;
fixture.detectChanges();
});

it('should create', () => {
expect(component).toBeTruthy();
});
});
37 changes: 37 additions & 0 deletions src/app/new-contact/new-contact.component.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
import { Component, OnInit } from '@angular/core';
import { FormBuilder, FormGroup, Validators } from '@angular/forms';
import { ContactService, Contact } from '../contact.service';
import { Router } from '@angular/router';

@Component({
selector: 'app-new-contact',
templateUrl: './new-contact.component.html',
styleUrls: ['./new-contact.component.css']
})
export class NewContactComponent implements OnInit {
contactForm!: FormGroup;

constructor(
private fb: FormBuilder,
private contactService: ContactService,
private router: Router
) { }

ngOnInit(): void {
this.contactForm = this.fb.group({
name: ['', Validators.required],
email: ['', [Validators.required, Validators.email]]
});
}

onSubmit(): void {
if (this.contactForm.valid) {
const newContact: Contact = {
id: this.contactService.getContacts().length + 1, // simpel id
...this.contactForm.value
};
this.contactService.addContact(newContact);
this.router.navigate(['/contacts']); // terug naar lijst
}
}
}
Empty file.
8 changes: 8 additions & 0 deletions src/app/view-contact/view-contact.component.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
<div *ngIf="contact; else notFound">
<h2>{{ contact.name }}</h2>
<p>Email: {{ contact.email }}</p>
</div>

<ng-template #notFound>
<p>Contact not found!</p>
</ng-template>
23 changes: 23 additions & 0 deletions src/app/view-contact/view-contact.component.spec.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
import { ComponentFixture, TestBed } from '@angular/core/testing';

import { ViewContactComponent } from './view-contact.component';

describe('ViewContactComponent', () => {
let component: ViewContactComponent;
let fixture: ComponentFixture<ViewContactComponent>;

beforeEach(async () => {
await TestBed.configureTestingModule({
imports: [ViewContactComponent]
})
.compileComponents();

fixture = TestBed.createComponent(ViewContactComponent);
component = fixture.componentInstance;
fixture.detectChanges();
});

it('should create', () => {
expect(component).toBeTruthy();
});
});
22 changes: 22 additions & 0 deletions src/app/view-contact/view-contact.component.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
import { Component, OnInit } from '@angular/core';
import { ActivatedRoute } from '@angular/router';
import { ContactService, Contact } from '../contact.service';

@Component({
selector: 'app-view-contact',
templateUrl: './view-contact.component.html',
styleUrls: ['./view-contact.component.css']
})
export class ViewContactComponent implements OnInit {
contact: Contact | undefined;

constructor(
private route: ActivatedRoute,
private contactService: ContactService
) { }

ngOnInit(): void {
const id = Number(this.route.snapshot.paramMap.get('id'));
this.contact = this.contactService.getContactById(id);
}
}