Overview
The Patient component provides a comprehensive list view of all patients with search functionality, filtering capabilities, and quick actions for creating new appointments and managing patient records.
Component Definition
selector
string
default: "app-patient"
The CSS selector used to include this component in templates
Standalone component with explicit imports
Dependencies: CommonModule, FormsModule, RouterModule, NewAppointment
Source Code Location
File : src/app/patient/patient.ts:8
import { Component , OnInit } from '@angular/core' ;
import { CommonModule } from '@angular/common' ;
import { FormsModule } from '@angular/forms' ;
import { RouterModule } from '@angular/router' ;
import { PatientService , PatientData } from '../services/patient.service' ;
import { NewAppointment } from '../new-appointment/new-appointment' ;
@ Component ({
selector: 'app-patient' ,
standalone: true ,
imports: [ CommonModule , FormsModule , RouterModule , NewAppointment ],
templateUrl: './patient.html' ,
styleUrl: './patient.css' ,
})
export class Patient implements OnInit {
searchText : string = '' ;
patients : PatientData [] = [];
isNewAppointmentModalOpen : boolean = false ;
constructor ( private patientService : PatientService ) { }
ngOnInit () : void {
this . patients = this . patientService . getPatients ();
}
get filteredPatients () {
if ( ! this . searchText ) {
return this . patients ;
}
const search = this . searchText . toLowerCase ();
return this . patients . filter ( p =>
( p . nombre ?. toLowerCase (). includes ( search ) || false ) ||
( p . email ?. toLowerCase (). includes ( search ) || false ) ||
( p . phone ?. includes ( search ) || false )
);
}
openNewAppointmentModal () : void {
this . isNewAppointmentModalOpen = true ;
}
closeNewAppointmentModal () : void {
this . isNewAppointmentModalOpen = false ;
}
}
Properties
searchText
The current search query entered by the user
This property is bound to the search input using two-way binding ([(ngModel)]), automatically updating as the user types.
Implementation : src/app/patient/patient.ts:16
patients
patients
PatientData[]
default: "[]"
Array of all patient records loaded from the service
Populated during ngOnInit() by calling patientService.getPatients().
Implementation : src/app/patient/patient.ts:17
isNewAppointmentModalOpen
isNewAppointmentModalOpen
Controls the visibility of the new appointment modal
Implementation : src/app/patient/patient.ts:18
Computed Properties
filteredPatients
Getter that returns filtered patients based on the search text
Filters patients by matching the search text against:
Patient name (nombre)
Email address (email)
Phone number (phone)
The search is case-insensitive and returns all patients if the search text is empty.
Implementation : src/app/patient/patient.ts:26-36
get filteredPatients () {
if ( ! this . searchText ) {
return this . patients ;
}
const search = this . searchText . toLowerCase ();
return this . patients . filter ( p =>
( p . nombre ?. toLowerCase (). includes ( search ) || false ) ||
( p . email ?. toLowerCase (). includes ( search ) || false ) ||
( p . phone ?. includes ( search ) || false )
);
}
Methods
ngOnInit()
Lifecycle hook that loads patient data when the component initializes
ngOnInit (): void {
this . patients = this . patientService . getPatients ();
}
Implementation : src/app/patient/patient.ts:22-24
openNewAppointmentModal()
Opens the new appointment modal dialog
Implementation : src/app/patient/patient.ts:38-40
closeNewAppointmentModal()
Closes the new appointment modal dialog
Implementation : src/app/patient/patient.ts:42-44
Template Structure
The component template is organized into several sections:
Title : “Pacientes”
Description : “Gestión de pacientes de la clínica”
Nueva Cita button : Opens appointment modal
Nuevo Paciente button : Navigates to /patient/new
Search Section
Search input with icon and two-way binding to searchText < input type = "text"
placeholder = "Buscar por nombre, email o teléfono..."
[(ngModel)] = "searchText" >
Table Section
Columns
Data Binding
Actions
Paciente : Name and age
Contacto : Phone and email with icons
Última Visita : Date of last visit
Próxima Cita : Date of next appointment
Estado : Status badge (activo, pendiente, urgente)
Acciones : View details link
< tr *ngFor = "let patient of filteredPatients" >
< td >
< div class = "patient-info" >
< span class = "patient-name" > {{ patient.nombre }} </ span >
< span class = "patient-age" > {{ patient.edad }} años </ span >
</ div >
</ td >
<!-- other columns -->
</ tr >
Each row has a “Ver detalles” link: < a [routerLink] = "['/patient', patient.id]" class = "view-details" >
< span class = "view-icon" >< i class = "fa-solid fa-eye" ></ i ></ span > Ver detalles
</ a >
Modal Overlay
Displays the new appointment modal when isNewAppointmentModalOpen is true < div class = "modal-overlay" *ngIf = "isNewAppointmentModalOpen"
(click) = "closeNewAppointmentModal()" >
< div class = "modal-content" (click) = "$event.stopPropagation()" >
< app-new-appointment
(close) = "closeNewAppointmentModal()"
(created) = "closeNewAppointmentModal()" >
</ app-new-appointment >
</ div >
</ div >
PatientData Interface
The component works with the PatientData interface:
export interface PatientData {
id : number ;
nombre : string ;
edad : number ;
phone : string ;
email : string ;
address : string ;
medication_allergies : string ;
billing_data : string ;
health_status : string ;
family_history : string ;
ultimaVisita : string ;
proximaCita : string ;
estado : string ;
citas : Cita [];
tratamientos : Tratamiento [];
}
Service Integration
The component depends on PatientService for data operations:
Retrieves all patient records from the service
constructor ( private patientService : PatientService ) { }
ngOnInit (): void {
this . patients = this . patientService . getPatients ();
}
Usage Example
The Patient component is typically used as a routed component:
import { Routes } from '@angular/router' ;
import { Patient } from './patient/patient' ;
export const routes : Routes = [
{
path: 'patient' ,
component: Patient ,
data: { title: 'Pacientes' }
}
];
Status Badge Styling
The status badge uses dynamic CSS classes:
< span class = "status-badge" [ngClass] = "patient.estado" >
{{ patient.estado }}
</ span >
Status Values :
activo: Active patient (green)
pendiente: Pending patient (yellow)
urgente: Urgent patient (red)
Search Functionality
The search feature provides real-time filtering:
User Types
User enters search text in the input field
Two-way Binding
[(ngModel)] updates searchText property automatically
Getter Recomputes
filteredPatients getter is called on each change detection cycle
Table Updates
Template rerenders with filtered results
Modal Integration
The component embeds the NewAppointment component in a modal:
Event Handling
Emitted when the user closes the appointment modal
Emitted when a new appointment is successfully created
Both events trigger closeNewAppointmentModal() to dismiss the modal.
Click-Outside Detection
< div class = "modal-overlay" (click) = "closeNewAppointmentModal()" >
< div class = "modal-content" (click) = "$event.stopPropagation()" >
<!-- modal content -->
</ div >
</ div >
Clicking the overlay closes the modal, while clicking inside the modal prevents propagation.
Router Navigation
The component uses RouterModule for navigation:
View Patient Details
< a [routerLink] = "['/patient', patient.id]" class = "view-details" >
Ver detalles
</ a >
Navigates to /patient/{id} to view detailed patient information.
New Patient
< button class = "btn-new" routerLink = "/patient/new" >
Nuevo Paciente
</ button >
Navigates to /patient/new to create a new patient record.
Customization
Add Additional Search Fields
Extend the filtering logic to include more fields:
get filteredPatients () {
if ( ! this . searchText ) {
return this . patients ;
}
const search = this . searchText . toLowerCase ();
return this . patients . filter ( p =>
( p . nombre ?. toLowerCase (). includes ( search ) || false ) ||
( p . email ?. toLowerCase (). includes ( search ) || false ) ||
( p . phone ?. includes ( search ) || false ) ||
( p . address ?. toLowerCase (). includes ( search ) || false )
);
}
Add Sorting
Implement column sorting:
export class Patient implements OnInit {
sortColumn : string = '' ;
sortDirection : 'asc' | 'desc' = 'asc' ;
sortBy ( column : string ) : void {
if ( this . sortColumn === column ) {
this . sortDirection = this . sortDirection === 'asc' ? 'desc' : 'asc' ;
} else {
this . sortColumn = column ;
this . sortDirection = 'asc' ;
}
}
get filteredPatients () {
let filtered = /* existing filter logic */ ;
if ( this . sortColumn ) {
filtered = filtered . sort (( a , b ) => {
const aVal = a [ this . sortColumn ];
const bVal = b [ this . sortColumn ];
const modifier = this . sortDirection === 'asc' ? 1 : - 1 ;
return aVal > bVal ? modifier : - modifier ;
});
}
return filtered ;
}
}
Implement pagination for large patient lists:
export class Patient implements OnInit {
currentPage : number = 1 ;
pageSize : number = 10 ;
get paginatedPatients () {
const filtered = this . filteredPatients ;
const start = ( this . currentPage - 1 ) * this . pageSize ;
return filtered . slice ( start , start + this . pageSize );
}
get totalPages () {
return Math . ceil ( this . filteredPatients . length / this . pageSize );
}
}
Patient Service Service for patient data management
Patient Management Patient management feature documentation
Appointment View Appointment listing component
Menu Navigation menu component