angular-reservation
  • Demo
  • Documentation
  • API Documentation
  • View on GitHub

angular-reservation

AngularJS module to set up an appointment on a calendar. It can be used to make a reservation in a restaurant, clinic, barber shop, or any kind of service provided in time slots

Demo

This is a hardcoded demo that always return the same list of available hours. You can see an API REST implementation example here

Basic usage

Documentation

Getting started

Load scripts

Load AngularJS, dependencies script files and the script file angular-reservation.min.js in your index.html.


                    <!-- Angular reservation dependencies -->
                    <script type="text/javascript" src="bower_components/angular-bootstrap/ui-bootstrap.min.js"></script>
                    <script type="text/javascript" src="bower_components/angular-bootstrap/ui-bootstrap-tpls.min.js"></script>
                    <script type="text/javascript" src="bower_components/angular-translate/angular-translate.min.js"></script>
                    <script src="bower_components/angular-messages/angular-messages.min.js"></script>
                    <!-- Angular reservation minified -->
                    <script type="text/javascript" src="bower_components/angular-reservation/dist/angular-reservation.min.js"></script>
                
Load styles

Load bootstrap css and angular-reservation.min.css in your index.html.


                    <!-- Compiled and minified Bootstrap CSS -->
                    <link rel="stylesheet" href="components/bootstrap/bootstrap.min.css">
                    <!-- Angular reservation minified css -->
                    <link rel="stylesheet" href="bower_components/angular-reservation/dist/angular-reservation.min.css">
                
Add module dependency

Add 'hm.reservation' to the list of module dependencies.


                    angular.module('myApp', [
                        'hm.reservation'
                    ])
                
HTML Markup

Add angular-reservation directive in an html page.


                    <!-- angular-reservation directive -->
                    <reservation></reservation>
                
Setup

                    //Configuration of reservation module
                    angular.module('myApp').config(function (reservationConfigProvider) {
                        var config = {
                            getAvailableHoursAPIUrl: "http://API-URL/availableHours", //API url endpoint to load list of available hours
                            reserveAPIUrl: "http://API-URL/reserve", //API url endpoint to do a reserve
                        };

                        reservationConfigProvider.set(config);
                    });
                

Configuration options

You can configure angular-reservation module during config phase passing configuration options.

  • getAvailableDatesFromAPI: Enable/disable load of available dates from a REST API. Default value is false.

  • getAvailableDatesAPIUrl: API URL to load list of available dates. Only needed if getAvailableDatesFromAPI option is true. Default value is: http://localhost:8080/availableDates.

  • getAvailableHoursAPIUrl: API URL to load list of available hours for selected date. Default value is: http://localhost:8080/availableHours.

  • reserveAPIUrl: API URL to reserve selected hour for selected date, passing client data JSON. Default value is: http://localhost:8080/reserve.

  • dateFormat: Date format to show selected date, can be any valid date format. Default value is "yyyy-MM-dd".

  • language: Language to be used, valid values are "en" for english and "es" for spanish. Default value is "en".

  • showConfirmationModal: Shows or not confirmation modal on reserve button click, valid values are true or false. Default value is true.

  • datepickerTemplate: Datepicker template to override default datepicker template, see examples above. Default value is datepicker.html.

  • availableHoursTemplate: Available hours template to override default available hours template, see examples above. Default value is availableHours.html.

  • noAvailableHoursTemplate: No available hours template to override default no available hours template, see examples above. Default value is noAvailableHours.html.

  • clientFormTemplate: Form template to override default client form, see examples above. Default value is clientForm.html.

  • confirmationModalTemplate: Modal template to override default confirmation modal, see examples above. Default value is confirmationModal.html.

Example

                    //Configuration of reservation module
                    angular.module('myApp').config(function (reservationConfigProvider) {
                        var config = {
                            getAvailableDatesFromAPI: false,
                            getAvailableDatesAPIUrl: "http://api-url/api/availableDates",
                            getAvailableHoursAPIUrl: "http://api-url/api/availableHours",
                            reserveAPIUrl: "http://api-url/api/reserve",
                            language: "es",
                            dateFormat: "dd/MM/yyyy",
                            showConfirmationModal: false,
                            datepickerTemplate: "partials/datepicker.html",
                            availableHoursTemplate: "partials/availableHours.html",
                            noAvailableHoursTemplate: "partials/noAvailableHours.html"
                            clientFormTemplate: "partials/clientFormTemplate.html",
                            confirmationModalTemplate: "partials/confirmModal.html"
                        };

                        reservationConfigProvider.set(config);
                    });
                
Loading available dates from a REST API
  • You can configure this module to load a list of available dates from a REST API. This can be useful if you need to enable only a few specific dates, otherwise, you should prefer using Datepicker options of the directive (see above).
  • To enable loading of available dates from a REST API you need to set getAvailableDatesFromAPI configuration option to true and set getAvailableDatesAPIUrl to the API URL that will handle the request (see API docs).
  • The loader will be shown while request is pending.
  • Available dates returned from the REST API should be in ISO 8061 format.

                    //Configuration of reservation module
                    angular.module('myApp').config(function (reservationConfigProvider) {
                        var config = {
                            getAvailableDatesFromAPI: true,
                            getAvailableDatesAPIUrl: "http://my-api-url/availableDates",
                            ...
                        };

                        reservationConfigProvider.set(config);
                    });
                
Overriding datepicker template
  • You can override datepicker template and use your preferred datepicker.
  • You can configure your datepicker with the datepicker options object you passed to the directive (See above). This options are available at reservationCtrl.datepickerOptions.
  • The model of your datepicker should be reservationCtrl.selectedDate.
  • When you select a date on your datepicker you should call reservationCtrl.onSelectDate() function.

                    <h3 class="text-center">Select an available date</h3>

                    <div style="width: 50%; margin: 0 auto">
                        <p class="input-group">
                            <input type="text" class="form-control" uib-datepicker-popup ng-model="reservationCtrl.selectedDate" is-open="isOpen"
                                   datepicker-options="reservationCtrl.datepickerOptions" ng-change="reservationCtrl.onSelectDate()"/>
                            <span class="input-group-btn">
                                <button type="button" class="btn btn-default" ng-click="isOpen = !isOpen"><i class="glyphicon glyphicon-calendar"></i></button>
                            </span>
                        </p>
                    </div>
                
Overriding available hours template
  • This template is shown after get available hours request if available hours array is not empty.
  • The list of available hours is available at reservationCtrl.availableHours.
  • The model for selected hour should be reservationCtrl.selectedHour.
  • When you select an hour you should call reservationCtrl.selectHour(hour) function passing selected hour by parameter.
  • The status of get available hours request will be available at reservationCtrl.availableHoursStatus and additional message is available at reservationCtrl.availableHoursMessage.

                    <h3 class="text-center">Select an available hour</h3>

                    <div ng-repeat="hour in reservationCtrl.availableHours" ng-click="reservationCtrl.selectHour(hour)">
                        <div ng-class="{'selected': reservationCtrl.selectedHour == hour}" class="hour">
                            <span>{{hour}}</span>
                        </div>
                    </div>

                    <style>
                        .hour{
                            border: 1px solid black;
                            border-radius: 4px;
                            text-align: center;
                            padding: 1em 1em;
                            margin: 1em 1em;
                            cursor: pointer;
                        }
                    </style>
                
Overriding no available hours template
  • This template is shown after get available hours request if available hours array is empty.
  • The status of get available hours request will be available at reservationCtrl.availableHoursStatus and additional message is available at reservationCtrl.availableHoursMessage.

                     <div>
                        <h3 class="text-justify" style="padding: 2em 2em;">Oh no! There is no available hours for selected date, try another date!</h3>
                    </div>
                
Overriding client form template
  • All client data inputs should have an ng-model pointing to a property in reservationCtrl.userData JSON.
  • The form to do validations is available at reserveForm.
  • There should be one button with type="submit".
  • The status of reserve request will be available at reservationCtrl.reservationStatus and additional message is available at reservationCtrl.reservationMessage.

                    <div class="form-group col-md-12">
                        <label class="col-md-4 control-label" for="name">Name</label>
                        <div class="col-md-8">
                            <input id="name" name="name" class="form-control" placeholder="{{'name' | translate}}" type="text" ng-model="reservationCtrl.userData.name"
                                   autofocus="true" ng-pattern="/^[\w\s\-\x7f-\xff]*$/" ng-minlength="2" ng-maxlength="100" required>

                            <div class="help-block" ng-messages="reserveForm.name.$error" ng-if="reserveForm.$submitted">
                                <p ng-message="minlength" class="text-danger">{{"minLength" | translate: '{minLength: "2"}'}}</p>
                                <p ng-message="maxlength" class="text-danger">{{"maxLength" | translate: '{maxLength: "100"}'}}</p>
                                <p ng-message="pattern" class="text-danger">{{"invalidCharacters" | translate}}</p>
                                <p ng-message="required" class="text-danger">{{"required" | translate}}</p>
                            </div>
                        </div>
                    </div>

                    <div class="form-group col-md-12">
                        <label class="col-md-4 control-label">Gender</label>
                        <div class="col-md-8">
                            <div class="radio">
                                <label>
                                    <input type="radio" name="gender" id="option1" value="Male" ng-model="reservationCtrl.userData.gender">
                                    Male
                                </label>
                            </div>
                            <div class="radio">
                                <label>
                                    <input type="radio" name="gender" id="option2" value="Female" ng-model="reservationCtrl.userData.gender">
                                    Female
                                </label>
                            </div>

                            <div class="help-block" ng-messages="reserveForm.gender.$error" ng-if="reserveForm.$submitted">
                                <p ng-message="required" class="text-danger">{{"required" | translate}}</p>
                            </div>
                        </div>
                    </div>

                    <div class="form-group col-md-12">
                        <label class="col-md-4 control-label" for="phone">Phone</label>
                        <div class="col-md-8">
                            <input id="phone" name="phone" class="form-control" placeholder="{{'phone' | translate}}" type="tel" ng-model="reservationCtrl.userData.phone"
                                   ng-pattern="/^[0-9]*$/" ng-minlength="5" ng-maxlength="15" required>

                            <div class="help-block" ng-messages="reserveForm.phone.$error" ng-if="reserveForm.$submitted">
                                <p ng-message="minlength" class="text-danger">{{"minLength" | translate: '{minLength: "5"}'}}</p>
                                <p ng-message="maxlength" class="text-danger">{{"maxLength" | translate: '{maxLength: "15"}'}}</p>
                                <p ng-message="pattern" class="text-danger">{{"invalidPhone" | translate}}</p>
                                <p ng-message="required" class="text-danger">{{"required" | translate}}</p>
                            </div>
                        </div>
                    </div>

                    <div class="form-group col-md-12">
                        <label class="col-md-4 control-label" for="age">Age</label>
                        <div class="col-md-8">
                            <select id="age" name="age" class="form-control" ng-model="reservationCtrl.userData.age" required>
                                <option value="18-25">Between 18 and 25</option>
                                <option value="25-40">Between 25 and 40</option>
                                <option value="40-65">Between 40 and 65</option>
                                <option value="+65">>65/option>
                            </select>

                            <div class="help-block" ng-messages="reserveForm.age.$error" ng-if="reserveForm.$submitted">
                                <p ng-message="required" class="text-danger">{{"required" | translate}}</p>
                            </div>
                        </div>
                    </div>

                    <div class="form-group">
                        <div class="col-md-12">
                            <button id="reserve" type="submit" name="reserve" class="btn btn-success">{{"reserve" | translate}}</button>
                        </div>
                    </div>
                
Overriding confirmation modal template
  • Template must be like angular-bootstrap modal template. Documentation for modal can be found here.
  • Cancel button should dismiss the modal.
  • Confirm button should close the modal.

                    <div class="modal-header">
                        <h3 class="modal-title">Confirm amazing stuff</h3>
                    </div>

                    <div class="modal-body">
                        <h4>Are you really really sure of what you are doing??</h4>
                        <h5>Let's the party started!!!</h5>
                    </div>

                    <div class="modal-footer">
                        <button class="btn btn-danger" type="button" ng-click="$dismiss()">Oh, no!</button>
                        <button class="btn btn-success" type="button" ng-click="$close()">Hell, yes!</button>
                    </div>
                

Datepicker options

You can pass datepicker options to angular-reservation directive to configure datepicker based on your needs. Datepicker option documentation can be found here.

HTML Markup

                    <reservation datepicker-options="myCtrl.datepickerOptions"></reservation>
                
Controller

                    //Controller
                    angular.module('myApp').controller('MyCtrl', function () {
                        var vm = this;

                        //Datepicker options
                        vm.datepickerOptions = {
                            minDate: new Date(), //Disabled date selection before today
                            showWeeks: false, //Don't show weeks
                            startingDay: 1, //Starting day at Monday
                            dateDisabled: myDisabledDates //Disabled dates
                        }

                        //Disabled dates
                        function myDisabledDates(dateAndMode) {
                            var date = dateAndMode.date;
                            var mode = dateAndMode.mode;
                            var day = date.getDate();
                            var dayOfWeek = date.getDay();
                            var month = date.getMonth();
                            //Disable dates on Sundays and from 1 to 15 of August
                            return (mode === 'day' && (dayOfWeek === 0) || (month === 7 && day in [1,2,3,4,5,6,7,8,9,10,11,12,13,14,15]));
                        }
                    });
                

Callbacks

There are some callbacks available at reservationService that can be use to do some business logic. Open browser console to see callback logging for demo.

  • onBeforeGetAvailableHours: Callback executed before get available hours request.

  • onCompletedGetAvailableHours: Callback executed when get available hours request is completed, independently of its status.

  • onSuccessfulGetAvailableHours: Callback executed when get available hours request is completed successfully.

  • onErrorGetAvailableHours: Callback executed when get available hours request is completed with an error response (400 Bad Request, 500 Internal Server Error, etc.).

  • onBeforeReserve: Callback executed before reserve request.

  • onCompletedReserve: Callback executed when reserve request is completed, independently of its status.

  • onSuccessfulReserve: Callback executed when reserve request is completed successfully.

  • onErrorReserve: Callback executed when reserve request is completed with an error response (400 Bad Request, 500 Internal Server Error, etc.).

Example

                    angular.module('myApp').controller('MyCtrl', function ($q, reservationService) {
                        var vm = this;

                        //Reservation module callbacks
                        reservationService.onBeforeGetAvailableHours = function(selectedDate) {
                            console.log("Before get available hours! Selected date: " + selectedDate);
                            var deferred = $q.defer();

                            deferred.resolve();

                            return deferred.promise;
                        }

                        reservationService.onCompletedGetAvailableHours = function(statusLevel, message, selectedDate) {
                            console.log("Completed get available hours! Status level: " + statusLevel + ", message: " + message + ", selected date: " + selectedDate);
                        }

                        reservationService.onSuccessfulGetAvailableHours = function(statusLevel, message, selectedDate, availableHours) {
                            console.log("Successful get available hours! Status level: " + statusLevel + ", message: " + message + ", selected date: " + selectedDate + ", availableHours: " + availableHours);
                        }

                        reservationService.onErrorGetAvailableHours = function(statusLevel, message, selectedDate) {
                            console.log("Error get available hours! Status level: " + statusLevel + ", message: " + message + ", selected date: " + selectedDate);
                        }

                        reservationService.onBeforeReserve = function(selectedDate, selectedHour, userData) {
                            console.log("Before reserve! Selected date: " + selectedDate + ", selected hour: " + selectedHour + ", userData: " + JSON.stringify(userData));
                            var deferred = $q.defer();

                            deferred.resolve();

                            return deferred.promise;
                        }

                        reservationService.onCompletedReserve = function(statusLevel, message, selectedDate, selectedHour, userData) {
                            console.log("Completed reserve! Status level: " + statusLevel + ", message: " + message + ", selected date: " + selectedDate + ", selectedHour: " + selectedHour + ", userData: " + JSON.stringify(userData));
                        }

                        reservationService.onSuccessfulReserve = function(statusLevel, message, reservedDate, reservedHour, userData) {
                            console.log("Success reserve! Status level: " + statusLevel + ", message: " + message + ", reserved date: " + reservedDate + ", reserved hour: " + reservedHour + ", userData: " + JSON.stringify(userData));
                        }

                        reservationService.onErrorReserve = function(statusLevel, message, selectedDate, selectedHour, userData) {
                            console.log("Error reserve! Status level: " + statusLevel + ", message: " + message + ", selected date: " + selectedDate + ", selected hour: " + selectedHour + ", userData: " + JSON.stringify(userData));
                        }
                    });
                

API Documentation

See the API Documentation