How can I create a calendar with Angular where the first row is the places, the first column is the hours?
And the rest of the cells a space to put events.
For now I have this but I have the following problems,
-How can I add a border and the other thing is how do I place the rows of hours and places go hand in hand with the grid.
-My other problem is that the hours and places are dynamic when I create the grid template I have the values fixed.
HTML:
<div class="main-container">
<div class="stages-container-row">
<div>
<div *ngFor="let place of places">{{ place }}</div>
</div>
</div>
<div class="timing-container-column">
<div class="timings">
<div class="time">Time</div>
<div class="time" *ngFor="let hour of hours">
<span class="hour">
{{ hour }}
</span>
</div>
</div>
</div>
<ng-container *ngFor="let event of events">
<div class="slot" [ngStyle]="event.position">
<p>{{ event.location }}</p>
</div>
</ng-container>
CSS:
.main-container {
display: grid;
grid-template-columns: repeat(8, 1fr);
grid-template-rows: repeat(49, 1fr);
}
.stages-container-row {
grid-column: 2 / -1;
grid-row: 1 / 2;
}
[class^='stage']:nth-child(n + 2) {
grid-column: n + 2;
}
.details {
display: flex;
flex-direction: column;
}
.timing-container-column {
grid-column: 1 / 2;
grid-row: 1 / -1;
}
.timings {
height: 100%;
display: flex;
flex-direction: column;
justify-content: space-between;
}
.time {
display: flex;
justify-content: center;
align-items: center;
}
.slot {
flex-direction: column;
border: 1px solid red;
}
TS:
export class AppComponent implements AfterViewInit, OnInit {
interval = 30;
hourInit = 0;
minuteInit = 0;
hourEnd = 24;
minuteEnd = 0;
hours = [];
places = ['P1', 'P2', 'P3', 'P4', 'P5', 'P6'];
events: any = [];
constructor() {}
ngOnInit(): void {
this.generateHours();
}
generateHours() {
const start = this.hourInit * 60 + this.minuteInit;
const end = this.hourEnd * 60;
const periods = [];
for (let i = start; i < end; i += this.interval) {
periods.push(i);
}
this.hours = periods.map((period) => {
let hour =
Math.floor(period / 60)
.toString()
.padStart(2, '0') +
':' +
(period % 60).toString().padStart(2, '0');
return hour;
});
}
ngAfterViewInit() {
this.createEvent(1, 4, 'P3');
this.createEvent(16, 3, 'P1');
}
createEvent(period: number, duration: number, location: string) {
const event: any = { period, duration, location };
event.position = this.calculateEventPosition(period, duration, location);
this.events.push(event);
}
calculateEventPosition(period: number, duration: number, location: string) {
let position = {};
// Calculate start time of event
let startIndex = period - 1;
let startRow = startIndex + 2;
// Calculate end time of event
let endIndex = startIndex + duration;
let endRow = endIndex + 1;
// Calculate location of event
let locationIndex = this.places.indexOf(location);
let locationColumn = locationIndex + 1;
// Set grid-row position of event
position['grid-row'] = startRow + ' / ' + endRow;
// Set grid-column position of event
position['grid-column'] = locationColumn + ' / ' + (locationColumn + 1);
return position;
}
}
I plan to achieve what is in the image, but I ran into these problems.