इस गाइड में मीटिंग के कमरे बुक करने का कैलेंडर बनाया गया है: हर कमरे की एक पंक्ति वाली टाइमलाइन, ड्रैग करके सही जगह रखी जाने वाली बुकिंग, किसी कमरे की दोहरी बुकिंग रोकने वाला नियम, और बुकिंग को किसी भी कैलेंडर में जोड़ने वाली फ़ाइल। इसमें @needless-ui/angular का शेड्यूलर इस्तेमाल किया गया है, जो बाक़ी Needless UI की तरह MIT लाइसेंस के तहत है, इसलिए रिसोर्स टाइमलाइन किसी भी ऐप के लिए मुफ़्त है।
कमरे और बुकिंग
कमरे रिसोर्स हैं: एक id, एक title, और बाक़ी सब कुछ data में। बुकिंग सादे ISO समय वाले इवेंट हैं, जैसे 2026-10-23T09:00, और उनके कमरे की id resource में रहती है। एक बुकिंग में सूची के रूप में कई कमरे, या लोग, भी हो सकते हैं।
हर कमरे की एक पंक्ति
दोनों को view="timeline" के साथ nui-scheduler में पास करें। dayStart और dayEnd दिन को खुले रहने के घंटों तक सीमित रखते हैं, snapMinutes बुकिंग को 15-15 मिनट खिसकाता है, और businessHours उस समय को छायांकित करते हैं, जब कमरे बंद रहते हैं। nuiSchedulerResource हर पंक्ति का हेडर बनाता है।
<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>बुक करें और खिसकाएँ
शेड्यूलर आपका डेटा ख़ुद कभी नहीं बदलता: वह सिर्फ़ बताता है कि लोग क्या करते हैं। किसी कमरे की पंक्ति में ड्रैग करने से समय चुना जाता है, और slotSelect उसे कमरे के साथ बताता है। किसी बुकिंग को, या उसके अंत को, ड्रैग करने पर eventChange उसका नया समय बताता है, और अगर वह दूसरे कमरे में चली गई हो, तो उसका नया कमरा भी। सिग्नल अपडेट करें, और टाइमलाइन उसी के मुताबिक़ बदल जाएगी।
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');
}
}कोई दोहरी बुकिंग नहीं
कोई बुकिंग बनने या खिसकने से पहले allow से पूछा जाता है। अगर वह false लौटाता है, तो ड्रैग लाल दिखता है और छोड़ने पर कुछ नहीं होता, और कीबोर्ड से कोशिश करने पर शेड्यूलर बताता है कि वह समय उपलब्ध नहीं है। उदाहरण कमरे की बाक़ी बुकिंग जाँचता है; अपने सर्वर पर दोबारा जाँचें, क्योंकि आख़िरी फ़ैसला उसी का होता है।
स्क्रीन पर दिख रहे दिन लोड करें
rangeChange दिखाए गए पहले और आख़िरी दिन बताता है, एक बार शुरुआत में और फिर हर बार जब लोग पेज बदलते हैं, ताकि आप सिर्फ़ उन्हीं दिनों की बुकिंग ला सकें, httpResource से या अपनी पसंद की किसी भी रिक्वेस्ट से।
कैलेंडर में जोड़ें
nuiSchedulerToIcs() बुकिंग को एक iCalendar फ़ाइल के रूप में लिखता है, जिसे Google Calendar, Outlook और Apple Calendar इम्पोर्ट करते हैं। nuiSchedulerFromIcs() ऐसी फ़ाइल को वापस पढ़ता है, और दूसरे टाइम ज़ोन के समय को उपयोगकर्ता के टाइम ज़ोन में बदल देता है।
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);
}कीबोर्ड और स्क्रीन रीडर
यह सब माउस के बिना भी काम करता है। टाइमलाइन एक ही टैब स्टॉप है: ऐरो कुंजियाँ समय और कमरों के बीच चलती हैं, Shift के साथ ऐरो समय चुनते हैं, और Enter उसे बुक करता है। किसी बुकिंग पर, Alt के साथ ऐरो उसे दूसरे समय या कमरे में खिसकाते हैं। हर बुकिंग एक बटन है, जिसका नाम उसका टाइटल, कमरा, दिन और समय है।
दिन व्यू में अगल-बगल रखे कमरों, बार-बार होने वाली बुकिंग और बाक़ी सभी विकल्पों के लिए शेड्यूलर का पेज और उसका API देखें।