Monday, 29 September 2014

Using Bootstrap DateTimePicker

In this blog post I try to give a basic idea about how the Bootstrap DateTimePicker plugin can be used in an XPages application.

1. Minimal Requirements
- jQuery
- Moment.js
- Bootstrap.js
- Bootstrap Datetimepicker script
- Bootstrap CSS
- Bootstrap Datetimepicker CSS
- Optional Locales: Moment's locale files

2. Download Bootstrap DateTime Picker and Moment and add the files to the XPages Application
You can download the Bootstrap Datepicker file from GitHub : DateTimePicker
You can also download Moment from GitHub: Moment

Add the extracted files to the WebContent Folder (Package Explorer).

3 .Include moment.js, bootstrap-datepicker.js and bootstrap-datetimepicker.min.css on your XPage
The files / stylesheet  bootstrap-datetimepicker.min.css, bootstrap-datetimepicker.js and  moment.js must be included on the XPage or Application (Theme).
In this example I added the files directly to the XPage.
Note: In this example I use the OpenNTF Bootstrap4XPages plugin so the bootstrap files do not need to be added to the XPages separately.

<xp:script 
src="moment/moment.js"clientSide="true">
</xp:script>
<xp:script 
src="bootstrap-datetimepicker/js/bootstrap-datetimepicker.js"clientSide="true">
</xp:script>
<xp:styleSheet 
href="bootstrap-datetimepicker/css/bootstrap-datetimepicker.min.css">
</xp:styleSheet>

4. Using Bootstrap Datetimepicker
Basic Setup:
- Create a new XPage
- On the XPage add a Date Time Picker Control

Sample Code Basic Setup

<?xml version="1.0" encoding="UTF-8"?>
<xp:view xmlns:xp="http://www.ibm.com/xsp/core"
xmlns:xc="http://www.ibm.com/xsp/custom">
<xp:this.resources>
<xp:script src="moment/moment.js" clientSide="true"></xp:script>
<xp:script
src="bootstrap-datetimepicker/js/bootstrap-datetimepicker.js"
clientSide="true">
</xp:script>
<xp:styleSheet
href="bootstrap-datetimepicker/css/bootstrap-datetimepicker.min.css">
</xp:styleSheet>
</xp:this.resources>
<xp:this.data>
<xp:dominoDocument var="document1" formName="Contact"></xp:dominoDocument>
</xp:this.data>
 <xc:ccLayoutBootstrap>
<xp:this.facets>
<xp:panel xp:key="facetMiddle">
<div class="page-header">
<h1>
Datetimepicker
<xp:span style="color:rgb(255,255,255)">
</xp:span>
<small>Bootstrap plugin</small>
</h1>
</div>
<div class="col-sm-12">
<div class="form-group">
<div class='input-group date'
id='datetimepicker1'>
<xp:inputText id="inputText2"
styleClass="form-control">
<xp:this.converter>
<xp:convertDateTime type="both"
timeStyle="short" />
</xp:this.converter>
</xp:inputText>
<span class="input-group-addon">
<span
class="glyphicon glyphicon-calendar">
</span>
</span>
</div>
</div>
</div>
<xp:br></xp:br>
</xp:panel>
</xp:this.facets>
</xc:ccLayoutBootstrap>
<xp:scriptBlock id="scriptBlock1">
<xp:this.value><![CDATA[$(function () {
    $('#datetimepicker1').datetimepicker();
    });]]></xp:this.value>
</xp:scriptBlock>
</xp:view>

The result is a  good looking Bootstrap style Date Time Picker Control.

Important
Opening the XPage for the first time gives the following error in Chrome's console:


In this blog post I use the solution provided by Mark Leussink for this problem ( there is also a method to load the (JavaScript) resources before Dojo by Sven Hasselbach).
Cause: newer jQuery plugins try to use its AMD loader, but that doesn't play well with the Dojo implementation in XPages.
You have to hange the source code of the library . 
In the JavaScript file (bootstrap-datetimepicker.js) find the lines that determine if it can use the AMD loader. 
They can mostly be found at the beginning or end of a JavaScript file.

Below the modifications made in the bootstrap-datetimepicker.js file.

;(function (root, factory) {
    'use strict';
    //if (typeof define === 'function' && define.amd) {
         //AMD is used - Register as an anonymous module.
        define(['jquery', 'moment'], factory);
    //} else if (typeof exports === 'object') {
   //     factory(require('jquery'), require('moment'));
   // }
   // else {
        // Neither AMD or CommonJS used. Use global variables.
        if (!jQuery) {
            throw new Error('bootstrap-datetimepicker requires jQuery to be loaded first');
        }
        if (!moment) {
            throw new Error('bootstrap-datetimepicker requires moment.js to be loaded first');
        }
        factory(root.jQuery, moment);
    //}
}(this, function ($, moment) {
    'use strict';
    if (typeof moment === 'undefined') {
        throw new Error('momentjs is required');
    }


5. Customization / options
It is possible to customize the Bootstrap Date Time Picker with a lot of options / attributes.
For example, disable the Time or Date Picker, display time and date side by side or disable one or more days of the week in the date picker.
See the documentation for all options : Documentation
In the examples below I show a few of these customizations / options.

It is also possible to use attributes.

<xp:this.attrs>
   <xp:attr name="data-date-format"
     value="DD-MM-YYYY">
   </xp:attr>
</xp:this.attrs>

Sample Code Bootstrap Datetimepicker

<?xml version="1.0" encoding="UTF-8"?>
<xp:view xmlns:xp="http://www.ibm.com/xsp/core"
xmlns:xc="http://www.ibm.com/xsp/custom">

<xp:this.resources>
<xp:script src="moment/moment.js" clientSide="true"></xp:script>
<xp:script
src="bootstrap-datetimepicker/js/bootstrap-datetimepicker.js"
clientSide="true">
</xp:script>
<xp:styleSheet
href="bootstrap-datetimepicker/css/bootstrap-datetimepicker.min.css">
</xp:styleSheet>
</xp:this.resources>

<xp:this.data>
<xp:dominoDocument var="document1" formName="Contact"></xp:dominoDocument>
</xp:this.data>

<xc:ccLayoutBootstrap>
<xp:this.facets>
<xp:panel xp:key="facetMiddle">
<div class="page-header">
<h1>
Datetimepicker
<xp:span style="color:rgb(255,255,255)">
</xp:span>
<small>Bootstrap plugin</small>
</h1>
</div>
 
    Format date and placeholder with an Attribute
<div class="col-sm-12">
<div class="form-group">
<div class='input-group date'
id='datetimepicker1'>
<xp:inputText id="inputText2"
styleClass="form-control" value="#{document1.DateOfBirth}">
<xp:this.attrs>
<xp:attr name="data-date-format"
value="DD-MM-YYYY hh:mm:ss">
</xp:attr>
<xp:attr name="placeholder"
value="Enter data and time">
</xp:attr>
</xp:this.attrs>
<xp:this.converter>
<xp:convertDateTime type="date"
dateStyle="short">
</xp:convertDateTime>
</xp:this.converter>
</xp:inputText>
<span class="input-group-addon">
<span
class="glyphicon glyphicon-calendar">
</span>
</span>
</div>
</div>
</div>
<xp:br></xp:br>
 
    Disable Time Picker and Days of Week
<div class="col-sm-12">
<div class="form-group">
<div class='input-group date' id='datetimepicker2'>
<xp:inputText id="inputText1"
styleClass="form-control">
<xp:this.attrs>
<xp:attr name="data-date-format"
value="DD-MM-YYYY">
</xp:attr>
<xp:attr name="placeholder"
value="Enter a date">
</xp:attr>
</xp:this.attrs>
<xp:this.converter>
<xp:convertDateTime type="date"></xp:convertDateTime>
</xp:this.converter>
</xp:inputText>
<span class="input-group-addon">
<span
class="glyphicon glyphicon-calendar">
</span>
</span>
</div>
</div>
</div>
<xp:br></xp:br>
 
    Disable Time Picker
<div class="col-sm-12">
<div class="form-group">
<div class='input-group date'
id='datetimepicker3'>
<xp:inputText id="inputText3"
styleClass="form-control">
<xp:this.converter>
<xp:convertDateTime
type="date">
</xp:convertDateTime>
</xp:this.converter>
</xp:inputText>
<span class="input-group-addon">
<span
class="glyphicon glyphicon-clock">
</span>
</span>
</div>
</div>
</div>
<xp:br></xp:br>
 
    Select Date in Field and Icon
<div class="col-sm-12">
<div class="form-group">
<div id="datetimepicker4">
<div class='input-group date'>
<xp:inputText id="inputText4"
styleClass="form-control">
<xp:this.converter>
<xp:convertDateTime type="date">
</xp:convertDateTime>
</xp:this.converter>
<xp:this.attrs>
<xp:attr name="data-date-format"
value="DD-MM-YYYY">
</xp:attr>
</xp:this.attrs></xp:inputText>
<span class="input-group-addon">
<span
class="glyphicon glyphicon-calendar">
</span>
</span>
</div>
</div>
</div>
</div>
</xp:panel>
</xp:this.facets>
</xc:ccLayoutBootstrap>

  <xp:scriptBlock id="scriptBlock2">
<xp:this.value><![CDATA[$(function () {
                $('#datetimepicker1').datetimepicker({
                   pick12HourFormat: true,
                   sideBySide: true                               
                });
            });]]></xp:this.value>
</xp:scriptBlock>

  <xp:scriptBlock id="scriptBlock1">
<xp:this.value><![CDATA[$(function () {
                $('#datetimepicker2').datetimepicker({
                    pickTime: false,
                    daysOfWeekDisabled:[0,6]
                });
            });
]]></xp:this.value>
</xp:scriptBlock>

  <xp:scriptBlock id="scriptBlock3">
<xp:this.value><![CDATA[$(function () {
                $('#datetimepicker3').datetimepicker({
                    pickDate: false,
                    pick12HourFormat: true
                });
            });
]]></xp:this.value>
</xp:scriptBlock>
 
  <xp:scriptBlock id="scriptBlock4">
<xp:this.value><![CDATA[$(function () {
                $('#datetimepicker4').datetimepicker({
                    pickTime: false                    
                });
            });
]]></xp:this.value>
</xp:scriptBlock>
</xp:view>

No comments:

Post a Comment