diff --git a/src/app/app-routing.module.ts b/src/app/app-routing.module.ts
index 02972627..e125fc22 100644
--- a/src/app/app-routing.module.ts
+++ b/src/app/app-routing.module.ts
@@ -1,7 +1,16 @@
import { NgModule } from '@angular/core';
import { RouterModule, Routes } from '@angular/router';
+import { ListComponent } from './contacts/list/list.component';
+import { ViewComponent } from './contacts/view/view.component';
+import { AddComponent } from './contacts/add/add.component';
+import { EditComponent } from './contacts/edit/edit.component';
-const routes: Routes = [];
+const routes: Routes = [
+ { path: 'contacts', component: ListComponent },
+ { path: 'contacts/add', component: AddComponent },
+ { path: 'contacts/view/:id', component: ViewComponent },
+ { path: 'contacts/edit/:id', component: EditComponent },
+];
@NgModule({
imports: [RouterModule.forRoot(routes)],
diff --git a/src/app/app.module.ts b/src/app/app.module.ts
index 8207184c..cb337abb 100644
--- a/src/app/app.module.ts
+++ b/src/app/app.module.ts
@@ -4,10 +4,11 @@ import { BrowserModule } from '@angular/platform-browser';
import { AppRoutingModule } from './app-routing.module';
import { AppComponent } from './app.component';
import { LayoutModule } from './layout/layout.module';
+import { ContactsModule } from './contacts/contacts.module';
@NgModule({
declarations: [AppComponent],
- imports: [BrowserModule, AppRoutingModule, LayoutModule],
+ imports: [BrowserModule, AppRoutingModule, LayoutModule, ContactsModule, LayoutModule],
bootstrap: [AppComponent],
})
-export class AppModule {}
+export class AppModule { }
diff --git a/src/app/contacts/add/add.component.css b/src/app/contacts/add/add.component.css
new file mode 100644
index 00000000..04068da6
--- /dev/null
+++ b/src/app/contacts/add/add.component.css
@@ -0,0 +1,25 @@
+:host {
+ display: flex;
+ box-sizing: border-box;
+ width: 40vw;
+ flex-direction: column;
+}
+
+form {
+ display: flex;
+ flex-direction: column;
+ flex: 1;
+ gap: 0.5em;
+}
+
+label {
+ font-weight: bold;
+}
+
+.actions {
+ display: flex;
+}
+
+.spacer {
+ flex: 1;
+}
diff --git a/src/app/contacts/add/add.component.html b/src/app/contacts/add/add.component.html
new file mode 100644
index 00000000..2bc9116b
--- /dev/null
+++ b/src/app/contacts/add/add.component.html
@@ -0,0 +1,38 @@
+
Add Contact
+
diff --git a/src/app/contacts/add/add.component.ts b/src/app/contacts/add/add.component.ts
new file mode 100644
index 00000000..a93fcf88
--- /dev/null
+++ b/src/app/contacts/add/add.component.ts
@@ -0,0 +1,43 @@
+import { Component } from '@angular/core';
+import { FormBuilder, FormGroup, Validators } from '@angular/forms';
+import { Contact } from 'src/app/models/Contact';
+import { ContactForm } from 'src/app/models/ContactForm';
+import { ContactsService } from '../contacts.service';
+import { Router } from '@angular/router';
+
+@Component({
+ selector: 'app-add',
+ standalone: false,
+ templateUrl: './add.component.html',
+ styleUrl: './add.component.css'
+})
+export class AddComponent {
+ contactForm: FormGroup;
+
+ constructor(
+ private readonly formBuilder: FormBuilder,
+ private readonly contactsService: ContactsService,
+ private readonly router: Router
+ ) {
+ this.contactForm = this.formBuilder.group({
+ firstName: ['', Validators.required],
+ lastName: ['', Validators.required],
+ street: ['', Validators.required],
+ city: ['', Validators.required],
+ })
+ }
+
+ addContact(): void {
+ const newContact: Contact = {
+ id: this.contactsService.GetNextId(),
+ firstName: this.contactForm.value.firstName,
+ lastName: this.contactForm.value.lastName,
+ street: this.contactForm.value.street,
+ city: this.contactForm.value.city,
+ }
+
+ this.contactsService.AddContact(newContact);
+ this.contactForm.reset()
+ this.router.navigate(['/contacts'])
+ }
+}
diff --git a/src/app/contacts/contacts.module.ts b/src/app/contacts/contacts.module.ts
new file mode 100644
index 00000000..713f9ea7
--- /dev/null
+++ b/src/app/contacts/contacts.module.ts
@@ -0,0 +1,15 @@
+import { NgModule } from '@angular/core';
+import { CommonModule } from '@angular/common';
+import { ListComponent } from './list/list.component';
+import { AddComponent } from './add/add.component';
+import { ViewComponent } from './view/view.component';
+import { ReactiveFormsModule } from '@angular/forms';
+import { RouterModule } from '@angular/router';
+import { EditComponent } from './edit/edit.component';
+
+@NgModule({
+ declarations: [ListComponent, AddComponent, ViewComponent, EditComponent],
+ imports: [CommonModule, ReactiveFormsModule, RouterModule],
+ exports: [AddComponent, ListComponent, ViewComponent, EditComponent]
+})
+export class ContactsModule { }
diff --git a/src/app/contacts/contacts.service.ts b/src/app/contacts/contacts.service.ts
new file mode 100644
index 00000000..c2ecc9bc
--- /dev/null
+++ b/src/app/contacts/contacts.service.ts
@@ -0,0 +1,41 @@
+import { Injectable } from '@angular/core';
+import { Contact } from '../models/Contact';
+import { testContacts } from '../data/testContactData';
+import { Observable, of } from 'rxjs';
+
+@Injectable({
+ providedIn: 'root'
+})
+export class ContactsService {
+ public contacts: Contact[] = testContacts;
+
+ public AddContact(c: Contact): void {
+ this.contacts.push(c);
+ }
+
+ public EditContact(c: Contact): boolean {
+ const iToReplace = this.contacts.findIndex((curr) => (curr.id === c.id));
+
+ if (iToReplace > -1) {
+ this.contacts[iToReplace] = c;
+ return true;
+ } else {
+ return false;
+ }
+ }
+
+ public GetContactById(id: number): Observable {
+ const beer = this.contacts.find((c) => c.id === id);
+ return of(beer);
+ }
+
+ public GetNextId(): number {
+ if (this.contacts.length === 0) {
+ return 1;
+ }
+
+ return Math.max(...this.contacts.map(c => c.id)) + 1;
+ }
+
+ // constructor() { }
+}
diff --git a/src/app/contacts/edit/edit.component.css b/src/app/contacts/edit/edit.component.css
new file mode 100644
index 00000000..e69de29b
diff --git a/src/app/contacts/edit/edit.component.html b/src/app/contacts/edit/edit.component.html
new file mode 100644
index 00000000..e8f06aa1
--- /dev/null
+++ b/src/app/contacts/edit/edit.component.html
@@ -0,0 +1,67 @@
+@if (contact) {
+
+
+} @else {
+
+ Contact not found
+
+}
diff --git a/src/app/contacts/edit/edit.component.ts b/src/app/contacts/edit/edit.component.ts
new file mode 100644
index 00000000..ba7760aa
--- /dev/null
+++ b/src/app/contacts/edit/edit.component.ts
@@ -0,0 +1,76 @@
+import { Component } from '@angular/core';
+import { FormBuilder, FormGroup, Validators } from '@angular/forms';
+import { Contact } from 'src/app/models/Contact';
+import { ContactForm } from 'src/app/models/ContactForm';
+import { ContactsService } from '../contacts.service';
+import { ActivatedRoute, Router } from '@angular/router';
+
+@Component({
+ selector: 'app-edit',
+ standalone: false,
+ templateUrl: './edit.component.html',
+ styleUrl: './edit.component.css'
+})
+export class EditComponent {
+ contact: Contact | null = null;
+ contactId: number | null = null;
+ contactForm: FormGroup;
+
+ constructor(
+ private route: ActivatedRoute,
+ private readonly formBuilder: FormBuilder,
+ private readonly contactsService: ContactsService,
+ private readonly router: Router
+ ) {
+ this.contactForm = this.formBuilder.group({
+ firstName: [this.contact?.firstName],
+ lastName: [this.contact?.lastName],
+ street: [this.contact?.street],
+ city: [this.contact?.city],
+ })
+ }
+
+ ngOnInit(): void {
+ this.contactId = Number(this.route.snapshot.paramMap.get('id'));
+
+ if (!this.contactId) {
+ alert("Contact does not exist!")
+ this.router.navigate(['/contacts']);
+ return;
+ }
+
+ this.contactsService.GetContactById(this.contactId).subscribe(contact => {
+ this.contact = contact ?? null;
+
+ if (this.contact) {
+ this.contactForm.patchValue({
+ firstName: this.contact.firstName ?? '',
+ lastName: this.contact.lastName ?? '',
+ street: this.contact.street ?? '',
+ city: this.contact.city ?? ''
+ });
+ } else {
+ alert("Contact does not exist!")
+ this.router.navigate(['/contacts']);
+ return;
+ }
+ });
+ }
+
+ editContact(): void {
+ const newContact: Contact = {
+ id: this.contactId!,
+ firstName: this.contactForm.value.firstName,
+ lastName: this.contactForm.value.lastName,
+ street: this.contactForm.value.street,
+ city: this.contactForm.value.city,
+ }
+
+ const isUpdated: boolean = this.contactsService.EditContact(newContact);
+ if (!isUpdated) {
+ alert("Something went wrong when editing! Contact not updated!")
+ }
+ this.contactForm.reset()
+ this.router.navigate(['/contacts'])
+ }
+}
diff --git a/src/app/contacts/list/list.component.css b/src/app/contacts/list/list.component.css
new file mode 100644
index 00000000..22d0c2fc
--- /dev/null
+++ b/src/app/contacts/list/list.component.css
@@ -0,0 +1,13 @@
+:host {
+ display: flex;
+ box-sizing: border-box;
+ width: 40vw;
+ flex-direction: column;
+}
+
+.contact {
+ display: flex;
+ justify-content: space-between;
+ border-bottom: 1px solid #ddd;
+ padding: 0.5em 0;
+}
diff --git a/src/app/contacts/list/list.component.html b/src/app/contacts/list/list.component.html
new file mode 100644
index 00000000..f38965e6
--- /dev/null
+++ b/src/app/contacts/list/list.component.html
@@ -0,0 +1,19 @@
+Contacts
+
+@if (contacts) {
+
+} @else {
+No contacts yet
+}
diff --git a/src/app/contacts/list/list.component.ts b/src/app/contacts/list/list.component.ts
new file mode 100644
index 00000000..06ede3ba
--- /dev/null
+++ b/src/app/contacts/list/list.component.ts
@@ -0,0 +1,17 @@
+import { Component } from '@angular/core';
+import { Contact } from 'src/app/models/Contact';
+import { ContactsService } from '../contacts.service';
+
+@Component({
+ selector: 'app-list',
+ standalone: false,
+ templateUrl: './list.component.html',
+ styleUrl: './list.component.css'
+})
+export class ListComponent {
+ contacts: Contact[] = [];
+
+ constructor(private readonly contactsService: ContactsService) {
+ this.contacts = this.contactsService.contacts;
+ }
+}
diff --git a/src/app/contacts/view/view.component.css b/src/app/contacts/view/view.component.css
new file mode 100644
index 00000000..e69de29b
diff --git a/src/app/contacts/view/view.component.html b/src/app/contacts/view/view.component.html
new file mode 100644
index 00000000..2c6f52cf
--- /dev/null
+++ b/src/app/contacts/view/view.component.html
@@ -0,0 +1,11 @@
+@if (contact) {
+
+ {{ contact.firstName }} {{ contact.lastName }}
+ {{ contact.street }}, {{ contact.city }}
+
+}
+@else {
+
+ Contact not found
+
+}
diff --git a/src/app/contacts/view/view.component.ts b/src/app/contacts/view/view.component.ts
new file mode 100644
index 00000000..bb428fc7
--- /dev/null
+++ b/src/app/contacts/view/view.component.ts
@@ -0,0 +1,26 @@
+import { Component } from '@angular/core';
+import { ActivatedRoute } from '@angular/router';
+import { Contact } from 'src/app/models/Contact';
+import { ContactsService } from '../contacts.service';
+
+@Component({
+ selector: 'app-view',
+ standalone: false,
+ templateUrl: './view.component.html',
+ styleUrl: './view.component.css'
+})
+export class ViewComponent {
+ contact: Contact | null = null;
+ contactId: number | null = null;
+
+ constructor(private route: ActivatedRoute, private contactsService: ContactsService) { }
+
+ ngOnInit(): void {
+ this.contactId = Number(this.route.snapshot.paramMap.get('id'));
+ this.contactsService.GetContactById(this.contactId).subscribe((c) => {
+ c != undefined
+ ? this.contact = c
+ : this.contact = null
+ })
+ }
+}
diff --git a/src/app/data/testContactData.ts b/src/app/data/testContactData.ts
new file mode 100644
index 00000000..ef9334ad
--- /dev/null
+++ b/src/app/data/testContactData.ts
@@ -0,0 +1,82 @@
+import { Contact } from "../models/Contact";
+
+export const errorContact: Contact = {
+ id: -1,
+ firstName: "Error",
+ lastName: "Error",
+ street: "Error",
+ city: "Error",
+}
+
+export const testContacts: Contact[] = [
+ {
+ id: 1,
+ firstName: "Alice",
+ lastName: "Johnson",
+ street: "123 Maple St",
+ city: "Springfield",
+ },
+ {
+ id: 2,
+ firstName: "Bob",
+ lastName: "Smith",
+ street: "456 Oak Ave",
+ city: "Riverton",
+ },
+ {
+ id: 3,
+ firstName: "Charlie",
+ lastName: "Brown",
+ street: "789 Pine Rd",
+ city: "Lakeside",
+ },
+ {
+ id: 4,
+ firstName: "Diana",
+ lastName: "Miller",
+ street: "321 Birch Blvd",
+ city: "Hillview",
+ },
+ {
+ id: 5,
+ firstName: "Ethan",
+ lastName: "Davis",
+ street: "654 Cedar Ln",
+ city: "Brookfield",
+ },
+ {
+ id: 6,
+ firstName: "Fiona",
+ lastName: "Wilson",
+ street: "987 Walnut Dr",
+ city: "Fairview",
+ },
+ {
+ id: 7,
+ firstName: "George",
+ lastName: "Anderson",
+ street: "159 Cherry Ct",
+ city: "Riverside",
+ },
+ {
+ id: 8,
+ firstName: "Hannah",
+ lastName: "Thomas",
+ street: "753 Elm St",
+ city: "Greenville",
+ },
+ {
+ id: 9,
+ firstName: "Ian",
+ lastName: "Martinez",
+ street: "852 Willow Way",
+ city: "Sunnyvale",
+ },
+ {
+ id: 10,
+ firstName: "Julia",
+ lastName: "Clark",
+ street: "951 Poplar Pl",
+ city: "Meadowbrook",
+ },
+];
diff --git a/src/app/layout/menu/menu.component.html b/src/app/layout/menu/menu.component.html
index 7c5ec7a2..de504fe9 100644
--- a/src/app/layout/menu/menu.component.html
+++ b/src/app/layout/menu/menu.component.html
@@ -1,5 +1,5 @@
Menu
+ Show Contact
+ Add Contact
+
\ No newline at end of file
diff --git a/src/app/models/Contact.ts b/src/app/models/Contact.ts
new file mode 100644
index 00000000..9a4610e5
--- /dev/null
+++ b/src/app/models/Contact.ts
@@ -0,0 +1,7 @@
+export interface Contact {
+ id: number;
+ firstName?: string;
+ lastName?: string;
+ street?: string;
+ city?: string;
+}
diff --git a/src/app/models/ContactForm.ts b/src/app/models/ContactForm.ts
new file mode 100644
index 00000000..c29142f3
--- /dev/null
+++ b/src/app/models/ContactForm.ts
@@ -0,0 +1,6 @@
+export interface ContactForm {
+ firstName?: string;
+ lastName?: string;
+ street?: string;
+ city?: string;
+}
\ No newline at end of file