Pandhuan iki nggawe kalender kanggo mesen ruangan rapat: linimasa kanthi baris kanggo saben ruangan, pesenan sing diseret menyang panggonane, aturan sing njaga supaya ruangan ora dipesen kaping pindho, lan berkas sing nglebokake pesenan menyang kalender apa wae. Pandhuan iki nganggo pangatur jadhwal saka @needless-ui/angular, kanthi lisensi MIT kaya kabeh Needless UI, dadi linimasa sumber daya gratis kanggo aplikasi apa wae.

Ruangan lan pesenan

Ruangan iku sumber daya: saben ruangan duwe id, title, lan apa wae liyane ing data. Pesenan iku acara kanthi wektu ISO biasa, kayata 2026-10-23T09:00, lan id ruangane ing resource. Siji pesenan bisa ngemot sawetara ruangan, utawa wong, minangka dhaptar.

Siji baris kanggo saben ruangan

Terusna kekarone menyang nui-scheduler kanthi view="timeline". dayStart lan dayEnd mbatesi dina mung ing jam buka, snapMinutes mindhah pesenan saben seprapat jam, lan businessHours nyuremake wektu nalika ruangan tutup. nuiSchedulerResource nggambar header saben baris.

booking.html
<nui-scheduler
[events]="bookings()"
[resources]="rooms"
view="timeline"
dayStart="8"
dayEnd="19"
snapMinutes="15"
[businessHours]="hours"
editable
selectable
[allow]="free"
(slotSelect)="book($event)"
(eventChange)="move($event)"
(rangeChange)="range.set($event)"
>
<ng-template nuiSchedulerResource let-room>{{ room.title }}</ng-template>
</nui-scheduler>
<button nuiButton type="button" (click)="download()">Add to calendar</button>

Mesen lan mindhah

Pangatur jadhwal ora tau ngowahi data panjenengan dhewe: mung nglaporake apa sing ditindakake wong. Nyeret ing sadawane baris ruangan milih wektu, lan slotSelect nglaporake wektu kasebut bareng ruangane. Nyeret pesenan, utawa pungkasane, nglaporake wektu anyare ing eventChange, uga ruangan anyare yen dipindhah menyang ruangan liya. Anyari signal-e, lan linimasa bakal ngetutake.

booking.ts
import { Component, signal } from '@angular/core';
import { NuiButton } from '@needless-ui/angular/button';
import {
NuiScheduler,
type NuiSchedulerChange,
type NuiSchedulerEvent,
NuiSchedulerResourceTemplate,
type NuiSchedulerSlot,
} from '@needless-ui/angular/scheduler';
import { downloadIcs } from './booking-ics';

@Component({
selector: 'app-bookings',
imports: [NuiButton, NuiScheduler, NuiSchedulerResourceTemplate],
templateUrl: './booking.html',
})
export class Bookings {
/** Rooms are resources; bookings are events, with their room in `resource`. */
protected readonly rooms = [
{ id: 'atlas', title: 'Atlas' },
{ id: 'boreal', title: 'Boreal' },
];
protected readonly bookings = signal<NuiSchedulerEvent[]>([]);
/** Open on weekdays from 8:00 to 19:00: other time is shaded. */
protected readonly hours = [{ days: [1, 2, 3, 4, 5], start: '08:00', end: '19:00' }];
/** The days on screen: load their bookings when it changes. */
protected readonly range = signal<{ start: string; end: string } | null>(null);

protected book({ start, end, resource }: NuiSchedulerSlot): void {
const booking = { id: crypto.randomUUID(), title: 'New booking', start, end, resource };
this.bookings.update((all) => [...all, booking]);
}

protected move({ event, start, end, resource }: NuiSchedulerChange): void {
this.bookings.update((all) =>
all.map((b) =>
b.id === event.id ? { ...b, start, end, resource: resource ?? b.resource } : b,
),
);
}

/** A room holds one booking at a time. */
protected readonly free = (time: NuiSchedulerChange | NuiSchedulerSlot): boolean => {
const id = 'event' in time ? time.event.id : null;
const room = 'event' in time ? (time.resource ?? time.event.resource) : time.resource;
return !this.bookings().some(
(b) => b.id !== id && b.resource === room && b.start < time.end && b.end > time.start,
);
};

protected download(): void {
downloadIcs(this.bookings(), 'bookings');
}
}

Ora ana pesenan kaping pindho

allow ditakoni sadurunge pesenan digawe utawa dipindhah. Yen mbalekake false, seretan katon abang lan ora nyelehake apa-apa, lan saka keyboard pangatur jadhwal ngandhani yen wektu kasebut ora kasedhiya. Conto iki ngecek pesenan liyane ing ruangan kasebut; cek maneh ing server panjenengan, sing nduwe keputusan pungkasan.

Muat dina sing katon ing layar

rangeChange nglaporake dina kapisan lan pungkasan sing ditampilake, sepisan ing wiwitan lan maneh saben wong ganti kaca, dadi panjenengan bisa njupuk pesenan ing dina-dina kasebut wae, nganggo httpResource utawa request apa wae sing panjenengan karepake.

Tambahna menyang kalender

nuiSchedulerToIcs() nulis pesenan dadi berkas iCalendar, sing bisa diimpor Google Calendar, Outlook lan Apple Calendar. nuiSchedulerFromIcs() maca berkas kaya ngono, lan mindhah wektu saka zona wektu liya menyang zona wektu sing maca.

booking-ics.ts
import { type NuiSchedulerEvent, nuiSchedulerToIcs } from '@needless-ui/angular/scheduler';

/** Saves events as an .ics file, which Google Calendar, Outlook and Apple Calendar import. */
export function downloadIcs(events: readonly NuiSchedulerEvent[], name: string): void {
const file = new Blob([nuiSchedulerToIcs(events, { name })], { type: 'text/calendar' });
const link = document.createElement('a');
link.href = URL.createObjectURL(file);
link.download = `${name}.ics`;
link.click();
URL.revokeObjectURL(link.href);
}

Keyboard lan screen reader

Kabeh iki bisa dienggo tanpa mouse. Linimasa mung siji tab stop: tombol panah pindhah antarane wektu lan ruangan, Shift karo panah milih wektu, lan Enter mesen wektu kasebut. Ing pesenan, Alt karo panah mindhah pesenan menyang wektu utawa ruangan liya. Saben pesenan yaiku tombol sing dijenengi miturut judhul, ruangan, dina lan wektune.

Kanggo ruangan sing jejer ing sadina, pesenan sing mbaleni lan saben pilihan liyane, pirsani kaca pangatur jadhwal lan API-ne.