Professional Documents
Culture Documents
@Injectable({
providedIn: 'root',
})
Injectable Service: @Injectable is a decorator used to mark a class as available to an injector for
instantiation. Here, the ContactService is marked as injectable at the root level (providedIn:
'root'), which means Angular can provide this service
Constructor: Angular injects HttpClient into the service through its constructor. This allows the
service to use HttpClient to perform HTTP requests.
1. getAllContacts(): Observable<IContact[]> {
2. let dataUrl: string = `${this.serverUrl}/contacts`;
3. return this.httpClient
4. .get<IContact[]>(dataUrl)
5. .pipe(catchError(this.handleError));
6. }
7. getAllContacts: This method sends an HTTP GET request to
the server to retrieve all contacts. It returns an
Observable of type IContact[] that emits the response data.
getContact(contactId: string): Observable<IContact> {
if (!contactId) {
return throwError('Contact ID is missing or invalid');
}
const dataUrl: string = `${this.serverUrl}/contacts/${contactId}`;
return this.httpClient
.get<IContact>(dataUrl)
.pipe(catchError(this.handleError));
}
handleError(error: HttpErrorResponse) {
let errorMessage: string = '';
if (error.error instanceof ErrorEvent) {
errorMessage = `Error: ${error.error.message}`;
} else {
errorMessage = `Status: ${error.status} \n Message: ${error.message}`;
}
return throwError(errorMessage);
}
Observable:
An Observable is a powerful data stream that represents a sequence of values or events over time. It is
part of the Reactive Extensions for JavaScript (RxJS) library often used within Angular for handling
asynchronous operations such as HTTP requests, event handling, and more.
Observables can emit multiple values asynchronously and are used to handle data streams or sequences
over time. They allow you to work with asynchronous data and perform operations like mapping,
filtering, combining, and subscribing to handle the emitted values.
.pipe():
The .pipe() method in Angular is used to combine multiple operators sequentially to transform the
emitted values of an Observable.
Operators like map(), filter(), catchError(), tap(), etc., are part of RxJS and can be chained using .pipe() to
perform various operations on the emitted data from Observables.
This method enables you to create a chain of operations that are applied to the data stream emitted by
the Observable.
Constructor:
In Angular, the constructor is a TypeScript feature used in classes to initialize class properties and
perform necessary setup operations when an instance of the class is created.
In components, services, or other Angular constructs, the constructor is used to inject dependencies by
specifying them as parameters. Angular's dependency injection system uses constructors to provide
instances of services or other dependencies to the class.
IContact.ts – MODEL
export class IContact {
id? : string;
name: string;
email: string;
mobile: string;
}
APP-ROUTING.MODULE.TS
@NgModule({
imports: [RouterModule.forRoot(routes)],
exports: [RouterModule],
})
export class AppRoutingModule {}
1. The Routes array defines the mapping between URL paths and
components. In this example, we have the following routes:
o An empty path ('') redirects to the 'home' path.
o The 'home' path maps to the ContactManagerComponent.
o The 'edit/:contactId' path maps to the ContactManagerComponent and
allows passing a dynamic contactId parameter.
o The 'view/:contactId' path maps to the ViewContactComponent and
allows passing a dynamic contactId parameter.
o The ** path is a wildcard route that matches any URL
that doesn't match the defined routes. It maps to
the PageNotFoundComponent.
2. The AppRoutingModule class is decorated with @NgModule. Inside
the decorator, we import the RouterModule and call
the forRoot() method, passing in the routes array. This method
configures the router with the provided routes. Finally, we
export the RouterModule to make it available for other modules
to import.
APP.COMPONENT.HTML
<router-outlet></router-outlet>
APP.COMPONENT.TS
import { Component } from '@angular/core';
@Component({
selector: 'app-root',
templateUrl: './app.component.html',
styleUrl: './app.component.css'
})
export class AppComponent {
title = 'my-contact-app';
}
APP.MODULE.TS
import { NgModule } from '@angular/core';
import { BrowserModule } from '@angular/platform-browser';
import { FormsModule } from '@angular/forms';
import { NgbModule } from '@ng-bootstrap/ng-bootstrap';
import { HttpClientModule } from '@angular/common/http';
import { AppRoutingModule } from './app-routing.module';
import { ToastrModule } from 'ngx-toastr';
@NgModule({
declarations: [
AppComponent,
PageNotFoundComponent,
ContactManagerComponent,
AddContactComponent,
ViewContactComponent,
CardviewComponent,
TableviewComponent
],
imports: [
BrowserModule,
AppRoutingModule,
HttpClientModule,
FormsModule,
NgbModule,
ToastrModule.forRoot({
positionClass: 'toast-bottom-right',
})
],
providers: [],
bootstrap: [AppComponent]
})
export class AppModule { }
1. NgModule: The NgModule decorator is used to define a module
in Angular. It takes a metadata object as an argument,
which specifies the declarations, imports, providers, and
bootstrap components of the module.
2. declarations: The declarations property is an array that
contains the components, directives, and pipes that belong
to the module. In the provided code,
the AppComponent, PageNotFoundComponent, ContactManagerComponent, AddConta
ctComponent, ViewContactComponent, CardviewComponent,
and TableviewComponent are declared.
3. imports: The imports property is an array that contains the
modules that are required by the module. In the provided
code,
the BrowserModule, AppRoutingModule, HttpClientModule, FormsModule, NgbMod
ule, and ToastrModule are imported.
4. providers: The providers property is an array that contains
the services and other dependencies that are provided by
the module. In the provided code, no providers are
specified.
5. bootstrap: The bootstrap property is an array that contains
the components that should be bootstrapped when the module
is loaded. In the provided code, the AppComponent is
bootstrapped.
@Component({
selector: 'app-contact-manager',
templateUrl: './contact-manager.component.html',
styleUrl: './contact-manager.component.css',
})
export class ContactManagerComponent implements OnInit {
ngOnInit(): void {
this.getAllContactsFromServer();
}
switchToCardView(): void {
this.isCardView = true;
}
switchToTableView(): void {
this.isCardView = false;
}
<div class="row">
<div class="col">
<h1>Contact Information</h1>
<button
class="btn btn-light"
type="button"
[disabled]="isCardView"
(click)="switchToCardView()"
title="Switch to Card View"
[ngClass]="{ selected: isCardView }"
aria-hidden="true"
>
<i class="fa-solid fa-border-all fa-2x" aria-hidden="true"></i>
</button>
</div>
</div>
</div>
<div *ngIf="errorMessage">
<div class="container">
<div class="row">
<div class="col">
<p class="h4 text-danger fw-bold">{{ errorMessage }}</p>
</div>
</div>
</div>
</div>
<div *ngIf="!isCardView">
<app-tableview
[contacts]="contacts"
(deleteClick)="clickDeleteContact($event)"
></app-tableview>
</div>
</div>
1.
ngClass: The [ngClass] directive is used to conditionally apply
CSS classes to an element based on a certain condition. In
this case, it is used to apply the "selected" class to the
button when it is active.
2. *ngIf: The *ngIf directive is used to conditionally render
HTML elements based on a certain condition. In this case,
it is used to display an error message if there is an
error.
3. *ngFor: The *ngFor directive is used to iterate over a
collection and render HTML elements for each item in the
collection. In this case, it is used to display a card view
for each contact in the contacts array.
4. Event Binding: The (click) event binding is used to bind a
function to the click event of a button. It allows the
function to be executed when the button is clicked.
VIEW-CONTACT.TS
@Component({
selector: 'app-view-contact',
templateUrl: './view-contact.component.html',
styleUrls: ['./view-contact.component.css'],
})
constructor(
private activatedRoute: ActivatedRoute,
private contactService: ContactService,
private modalService: NgbModal,
private router: Router
) {}
ngOnInit(): void {
this.activatedRoute.paramMap.subscribe((param: ParamMap) => {
const contactId = param.get('contactId');
if (contactId) {
this.contactService.getContact(contactId).subscribe(
(data: IContact) => {
this.contact = data;
this.viewModal(this.modalContent);
},
(error) => {
this.errorMessage = error;
this.router.navigate(['/']);
}
);
}
});
}
viewModal(content: any) {
this.modalService
.open(content, { size: 'xl', backdrop: 'static' })
.result.then(
(result) => {
this.closeModal();
},
(reason) => {
console.log('Modal dismissed.');
}
);
}
closeModal() {
this.modalService.dismissAll('Modal Closed');
}
isNotEmpty() {
return Object.keys(this.contact).length > 0;
}
}
<ng-template #modalContent>
<div class="container mt-5 modal-view">
<div class="row">
<div class="col d-flex flex-row">
<button class="btn btn-light" routerLink="/" (click)="closeModal()">
<i class="fa fa-arrow-alt-circle-left"></i>
</button>
<p class="h3 fw-bold">Contact Information</p>
</div>
</div>
</div>
1.
*ngIf Directive: This directive is used to conditionally
render elements in the template based on a given
expression. In this code, it is used to display an error
message if there is any error.
2. ng-template Directive: This directive is used to define a
template that can be used later in the code. In this code,
it is used to define the modal content that will be
displayed when viewing the contact information.
3. *ngIf="isNotEmpty()": This expression is used with the ngIf
directive to check if the contact object is not empty. If
it is not empty, the contact information will be displayed.
Angular Component:
AddContactComponent
Introduction
The AddContactComponent is an Angular component that is responsible
for adding and updating contacts in a contact management
application. It provides a form for users to enter contact
information and submit the form to create or update a contact.
This component interacts with the ContactService to perform CRUD
operations on contacts.
Key Concepts
1. @ViewChild: This decorator is used to get a reference to a
child component or element in the template. In this
case, @ViewChild('contactForm', { static: false }) contactForm: NgForm; is used to
get a reference to the NgForm instance of the contact form
in the template.
2. OnInit: This interface is implemented by the component to
define the ngOnInit lifecycle hook. The ngOnInit method is called
after the component is initialized and is used to perform
any initialization logic.
3. IContact: This is an interface that defines the structure of a
contact object. It includes properties such as name, email,
and mobile.
4. ContactService: This is a service that provides methods for
performing CRUD operations on contacts. It is injected into
the AddContactComponent constructor to enable communication with
the backend server.
5. Router: This is a service provided by Angular that is used
for navigation between different routes in the application.
It is injected into the AddContactComponent constructor to
enable navigation to the home route after closing the
modal.
6. ToastrService: This is a service that provides methods for
displaying toast notifications. It is injected into
the AddContactComponent constructor to display success messages
after adding or updating a contact.
import { Component, ViewChild, OnInit } from '@angular/core';
import { Router } from '@angular/router';
import { NgForm } from '@angular/forms';
import { NgbActiveModal } from '@ng-bootstrap/ng-bootstrap';
import { ToastrService } from 'ngx-toastr';
@Component({
selector: 'app-add-contact',
templateUrl: './add-contact.component.html',
styleUrls: ['./add-contact.component.css'],
})
export class AddContactComponent implements OnInit {
@ViewChild('contactForm', { static: false }) contactForm: NgForm;
constructor(
private contactService: ContactService,
private router: Router,
private toastr: ToastrService,
private activeModal: NgbActiveModal
) {}
public getAllContactsFromServer() {
this.contactService.getAllContacts().subscribe(
(data: IContact[]) => {
this.contacts = data;
},
(error) => {
this.errorMessage = error;
}
);
}
• getAllContactsFromServer(): This method is used to fetch all the
contacts from the server and update the contacts array.
public submitForm() {
if (this.isEditMode) {
//MY UPDATE HERE
this.contactService
.updateContact(this.contact, this.contact.id)
.subscribe(
() => {
this.handleFormSubmission();
},
(error) => {
this.errorMessage = error;
}
);
} else {
//MY ADD HERE
this.contactService.createContact(this.contact).subscribe(
() => {
this.handleFormSubmission();
},
(error) => {
this.errorMessage = error;
}
);
}
}
• submitForm(): This method is called when the form is submitted.
If the component is in edit mode, it calls
the updateContact method of the ContactService to update the
contact. Otherwise, it calls the createContact method of
the ContactService to create a new contact.
public closeModal() {
this.router.navigate(['/']);
this.activeModal.close('Modal Closed');
this.contactForm.reset();
}
• closeModal(): This method is called when the modal is closed.
It navigates to the home route, closes the modal, and
resets the contact form.
private handleFormSubmission() {
this.closeModal();
this.getAllContactsFromServer();
this.toastr.success(
this.isEditMode ? 'Changes saved' : 'Successfully Added New Contact'
);
}
• handleFormSubmission(): This method is called after a successful
form submission. It closes the modal, fetches all the
contacts from the server, and displays a success message
using the ToastrService.
ADD-CONTACT.COMPONENT.HTML
<div *ngIf="errorMessage">
<div class="container">
<div class="row">
<div class="col">
<p class="h4 text-danger fw-bold">{{ errorMessage }}</p>
</div>
</div>
</div>
</div>
<!--ADD BUTTON-->
<button
[disabled]="!contactForm.valid"
class="btn btn-danger ms-3 add-btn fw-bold"
type="submit"
>
{{ isEditMode ? "Save Changes" : "Add Contact" }}
</button>
</div>
</form>
</div>
</div>
CARDVIEW.COMPONENT.TS
Key Concepts
1. @Input: The @Input decorator is used to pass data from a
parent component to a child component. In this case,
the contact property is an input property that receives the
contact information from the parent component.
2. @Output: The @Output decorator is used to emit events from a
child component to a parent component. In this case,
the deleteClick event is emitted when the user clicks on the
delete button, and the contact ID is passed as the event
payload.
3. NgbModal: The NgbModal service is provided by the ng-
bootstrap library and is used to open and control modal
windows in an Angular application. It allows the user to
edit contact details in a modal window.
4. Router: The Router service is provided by the Angular Router
module and is used for navigation between different views
or components in an Angular application. It is used to
navigate to the edit contact route and the home route.
The Cardview component is defined as a TypeScript class with
the @Component decorator. It has an HTML template and a CSS file
associated with it.
The component has an @Input property named contact that receives the
contact information from the parent component. It also has
an @Output property named deleteClick that emits the deleteClick event
when the user clicks on the delete button.
@Component({
selector: 'app-cardview',
templateUrl: './cardview.component.html',
styleUrl: './cardview.component.css',
})
export class CardviewComponent {
@Input() contact: IContact | undefined;
@Output() deleteClick: EventEmitter<string> = new EventEmitter<string>();
this.router.navigateByUrl(editContactRoute).then(() => {
const modalRef = this.modalService.open(AddContactComponent, {
centered: true,
size: 'sm',
});
modalRef.componentInstance.contact = contact;
modalRef.result.then(
(result) => {
this.router.navigate(['/']);
},
(reason) => {
console.log('Modal is dismissed.');
this.router.navigate(['/']);
}
);
});
}
This method is called when the user clicks on the edit button in the
card. It navigates to the edit contact route and opens a modal window
using the NgbModal service. The AddContactComponent is used as the content
of the modal, and the selected contact is passed to it. After the
modal is closed, the method navigates back to the home route.