Streamlining College Timetable Creation with Angular, Node js, and MongoDB

Devendran
6 min readJan 31, 2023

College Timetable Creation is a crucial aspect of college management, as it ensures smooth functioning of the classes and helps students plan their schedules.

Creating a timetable manually can be time-consuming and prone to errors, and that’s where technology comes in. In this blog, we’ll be discussing how to create a College Timetable Creation Model using Angular, Node.js, and MongoDB. These technologies allow for a fast, reliable, and user-friendly solution for college management to create, manage, and track their timetable.

By using Angular for the front-end, Node.js for the back-end, and MongoDB for storing the data, we can ensure a seamless and efficient process for creating a college timetable.

So let’s get started!

Now first lets create basic reactive form in angular

import { Component, OnInit } from '@angular/core';
import { FormBuilder, FormGroup, Validators } from '@angular/forms';
import { Router } from '@angular/router';
import { ToastrService } from 'ngx-toastr';
import { DepartmentService } from 'src/app/services/department/department.service';
import { LoaderService } from 'src/app/services/loader/loader.service';
import { SubjectService } from 'src/app/services/subject/subject.service';
import { TimeTableService } from 'src/app/services/time-table/time-table.service';

@Component({
selector: 'app-add-timetable',
templateUrl: './add-timetable.component.html',
styleUrls: ['./add-timetable.component.scss']
})
export class AddTimetableComponent implements OnInit {
timeTableDetails: FormGroup;
departments: any[] = [];
sectionList: any[] = [];
subjectsList: any[] = [];
constructor(
private fb: FormBuilder,
private departmentServe: DepartmentService,
private subjectsServe: SubjectService,
private timeTableServe: TimeTableService,
private toast: ToastrService,
private loader: LoaderService,
private router: Router,
) {
this.timeTableDetails = this.fb.group({
departmentName: ['', Validators.required],
year: ['', Validators.required],
section: ['', Validators.required],
timeTable: this.fb.group({
monday: this.fb.group({
1: [],
2: [],
3: [],
4: [],
5: [],
6: [],
7: [],
8: [],
}),
tuesday: this.fb.group({
1: [],
2: [],
3: [],
4: [],
5: [],
6: [],
7: [],
8: [],
}),
wednesday: this.fb.group({
1: [],
2: [],
3: [],
4: [],
5: [],
6: [],
7: [],
8: [],
}),
thursday: this.fb.group({
1: [],
2: [],
3: [],
4: [],
5: [],
6: [],
7: [],
8: [],
}),
friday: this.fb.group({
1: [],
2: [],
3: [],
4: [],
5: [],
6: [],
7: [],
8: [],
}),
})
})
}

// get department
async getDepartment(): Promise<void> {
try {
this.departments = await this.departmentServe.getDepartmentDetails();
} catch (error) {
console.log(error);

}
}

// get department by id
// get section list
async getDepartmentDetails(): Promise<void> {
try {
this.loader.show();
// this condition helps to get department id with the help of department name
let selectedDepartmentId: any = "";
const name = this.timeTableDetails.value.departmentName;
if (name !== '') {
this.departments.find((x: any) => {
if (x.departmentName === name) {
selectedDepartmentId = x.id;
}
})
}
const data = await this.departmentServe.getDepartmentById(selectedDepartmentId);
this.sectionList = data.years[this.timeTableDetails.value.year];
} catch (error) {
console.log(error);
this.toast.error('Fali to Load Section');
} finally {
this.loader.hide();
}
}

// get subjects
async getSubjects(): Promise<void> {
try {
this.subjectsList = await this.subjectsServe.getSubjects();
} catch (error) {
console.log(error);
}
}


// handle table submit

async handleSubmit(): Promise<void> {
try {
this.loader.show();
const data = this.timeTableDetails.value;
const result = await this.timeTableServe.createTimeTable(data);
this.toast.success(result.message);
this.router.navigate(['/timetable'])
} catch (error: any) {
console.log(error);
this.toast.error(error.error.message)
} finally {
this.loader.hide();
}
}

ngOnInit(): void {
this.getDepartment();
this.getSubjects();
}


}

The above code first gets the department details to create a time table after that it make api call to get the details of year and section of that particular department.

This form structure will have 8 periods per day you can change as per your requirements.

Now let create the basic table form UI in angular

<div class="container">
<form class="row" [formGroup]="timeTableDetails" (ngSubmit)="handleSubmit()">
<!-- depatment, year and section selection -->
<div class="col-12">
<div class="row">
<div class="col-lg-3 col-md-4">
<mat-form-field appearance="outline" class="w-100">
<mat-label>Department</mat-label>
<mat-select formControlName="departmentName">
<mat-option *ngFor="let department of departments" [value]="department.departmentName">
{{ department.departmentName }}
</mat-option>
</mat-select>
</mat-form-field>
</div>
<div class="col-lg-3 col-md-4">
<mat-form-field appearance="outline" class="w-100">
<mat-label>Year</mat-label>
<mat-select formControlName="year" (selectionChange)="getDepartmentDetails()">
<mat-option value="firstYear">First Year </mat-option>
<mat-option value="secondYear">Second Year </mat-option>
<mat-option value="thirdYear">Third Year </mat-option>
<mat-option value="fourthYear">Fourth Year </mat-option>
</mat-select>
</mat-form-field>
</div>
<div class="col-lg-3 col-md-4">
<mat-form-field appearance="outline" class="w-100">
<mat-label>Section</mat-label>
<mat-select formControlName="section">
<mat-option [value]="s?.section" *ngFor="let s of sectionList"> {{s?.section}}
</mat-option>
</mat-select>
</mat-form-field>
</div>
</div>
</div>
<!-- time table -->
<div class="col-12 table-responsive">
<table class="table table-bordered">
<thead>
<tr>
<th scope="col">Day/Period</th>
<th scope="col" *ngFor="let l of [1,2,3,4,5,6,7,8]">{{l}}</th>
</tr>
</thead>
<tbody formGroupName="timeTable">
<tr formGroupName="monday">
<th scope="row">Monday</th>
<td *ngFor="let s of [1,2,3,4,5,6,7,8]; index as i">
<mat-form-field appearance="outline" class="w-100">
<mat-label>Select Subject</mat-label>
<mat-select [formControlName]="i + 1">
<mat-option *ngFor="let sub of subjectsList" [value]="sub.subjectName">
{{ sub.subjectName }} / {{sub.subjectCode}}
</mat-option>
</mat-select>
</mat-form-field>
</td>
</tr>
<tr formGroupName="tuesday">
<th scope="row">Tuesday</th>
<td *ngFor="let s of [1,2,3,4,5,6,7,8]; index as i">
<mat-form-field appearance="outline" class="w-100">
<mat-label>Select Subject</mat-label>
<mat-select [formControlName]="i + 1">
<mat-option *ngFor="let sub of subjectsList" [value]="sub.subjectName">
{{ sub.subjectName }} / {{sub.subjectCode}}
</mat-option>
</mat-select>
</mat-form-field>
</td>
</tr>
<tr formGroupName="wednesday">
<th scope="row">Wednesday</th>
<td *ngFor="let s of [1,2,3,4,5,6,7,8]; index as i">
<mat-form-field appearance="outline" class="w-100">
<mat-label>Select Subject</mat-label>
<mat-select [formControlName]="i + 1">
<mat-option *ngFor="let sub of subjectsList" [value]="sub.subjectName">
{{ sub.subjectName }} / {{sub.subjectCode}}
</mat-option>
</mat-select>
</mat-form-field>
</td>
</tr>
<tr formGroupName="thursday">
<th scope="row">Thursday</th>
<td *ngFor="let s of [1,2,3,4,5,6,7,8]; index as i">
<mat-form-field appearance="outline" class="w-100">
<mat-label>Select Subject</mat-label>
<mat-select [formControlName]="i + 1">
<mat-option *ngFor="let sub of subjectsList" [value]="sub.subjectName">
{{ sub.subjectName }} / {{sub.subjectCode}}
</mat-option>
</mat-select>
</mat-form-field>
</td>
</tr>
<tr formGroupName="friday">
<th scope="row">Friday</th>
<td *ngFor="let s of [1,2,3,4,5,6,7,8]; index as i">
<mat-form-field appearance="outline" class="w-100">
<mat-label>Select Subject</mat-label>
<mat-select [formControlName]="i + 1">
<mat-option *ngFor="let sub of subjectsList" [value]="sub.subjectName">
{{ sub.subjectName }} / {{sub.subjectCode}}
</mat-option>
</mat-select>
</mat-form-field>
</td>
</tr>
</tbody>
</table>
</div>
<!-- form buttons -->
<div class="d-flex justify-content-end flex-wrap">
<div>
<a [routerLink]="['/timetable']" class="btn bg-danger text-white btn-sm me-3 rounded shadow">
<span class="h6">&#10006; </span>
Cancel
</a>
</div>
<div>
<button class="btn btn-primary btn-sm rounded shadow" [disabled]="timeTableDetails.invalid">
Create TimeTable
</button>
</div>
</div>
</form>
</div>

BackEnd structure for Attendance schema

Mongoose Schema

const mongoose = require("mongoose");
const options = {
timestamps: true,
};

const TimeTableSchema = new mongoose.Schema(
{
departmentName: {
type: String,
required: true,
},
year: {
type: String,
trim: true,
required: true,
},
section: {
type: String,
required: true,
},
timeTable: {
monday: {},
tuesday: {},
wednesday: {},
thursday: {},
friday: {},
}
},
options
);

module.exports = mongoose.model("timeTable", TimeTableSchema);

Create api for above schema

const timeTable = require("../../models/timetable");


// create new timetable
const createTimeTable = async (req, res, next) => {
try {
// checking timetable already exist for that section
const filters = {
departmentName: req.body.departmentName,
year: req.body.year,
section: req.body.section,
}
const table = await timeTable.findOne(filters);
if (table) return res.status(400).json({ message: 'TimeTable already exist in this section, try to delete existing or select different section' })
await timeTable.create(req.body);
return res.status(200).json({ message: 'successfully created' });
} catch (error) {
console.log(error);
next(error);
}
}

// get timetable
const getTimeTables = async (req, res, next) => {
try {
const result = await timeTable.find();
return res.status(200).json({data: result});
} catch (error) {
console.log(error);
next(error);
}
}


module.exports = {
createTimeTable,
getTimeTables
}

The output of timetable creating form look like this

And time table look like this

--

--