Click here to Skip to main content
14,303,639 members

Getting it right for your customers

Rate this:
2.00 (4 votes)
Please Sign up or sign in to vote.
2.00 (4 votes)
6 Aug 2018MIT
A custom date control to solve my customers needs and requirements

Introduction

As a consultant I am often asked what code I am most proud of. Over the years I’ve learned that what I am most proud of is not necessarily how elegant my code is but rather how elegant my final solution is for the customer.

Recently I was working on a couple of web pages which did not meet their intended purpose. The purpose of the page was to match the time frames of an external resource. That resource would process and report files based on complete months, years and quarters.

I quickly determined the current solution of having two date controls (start date and end date) to manage the ranges was not working for them. It allowed the entry of values which would not match the time frames of the external resource. In fact, the pages were deemed so in ineffective that they were not generally usable.

My solution was to create a date selector based off of a slider control from jQuery and JavaScript. Now the end user can select proper dates which are constrained by the rules defined above and the pages have now become usable. Most importantly, the customer was pleased with the final product.

Background

In all cases the slider can slide to the first day of the selected range and the last day of the range selected.

Given the date August 3, 2018 and the year range set from 2015 through 2018 the following would be selectable by the control.

Depending on mode, the granularity of the control changes.

The control has three modes:

1.      Display by years

a.      The selectable dates would be January 1, 2015 through December 31, 2017

b.      The formatted display dates would be 2015 through 2017

c.      Three possible selections

2.      Display by Quarters

a.      The selectable dates would be January 1, 2015 through June 30, 2018

b.      The formatted display dates would be 2015/Q1 through 2018/Q2

c.      Fourteen possible selections.

3.      Display by Months.

a.      The selectable dates would be January 1, 2015 through July 31, 2018

b.      The formatted display dates would be 1/1/2015 through 7/31/2018

c.      Forty-Three possible selections.

Here is a sample image of what the control will display for an end user. 

Image 1

Using the code

To use the DateSlider object, include the js file into the HTML file, ensuring that you include the jQuery and moment.js 

HTML

<link href="Content/themes/base/jquery-ui.css" rel="stylesheet" />
<script src="https://code.jquery.com/jquery-3.3.1.js"></script>
<script src="https://code.jquery.com/ui/1.12.1/jquery-ui.js"></script>
<script src="Scripts/moment.js"></script>
<script src="Scripts/DateRanger.js"></script>

After these, you will need to add some 'Glue code' to connect the DateSlider object to the controls on the page.

To start create a script section and add the following to initialize the control.

<script type="text/javascript">

   // Notice we can initialize for any year range, if nothing set, it uses current year
   // from current year - 3 years

    //var drs = new DateRanger(2012, 2020); Future dates will only validate to current year
    var drs = new DateRanger();
    //This is used to store the returned object from setCurrentDateView
    var cdv = {};

Next you will want to call the method setCurrentDateView with the values ('month','quarter' or 'year') on the page loaded event and the change view dropdown

function changeBasis() {
        cdv = drs.setCurrentDateView($('#ddlBasis').find(":selected").val()); //control sets view
        changeslider();
    }

$(function () {

        cdv = drs.setCurrentDateView('Month'); //control sets view

        //initializing slider and setting it's slide function
        $("#dateSlider").slider({
            range: true,
            max: cdv.eIndex,
            slide: function (event, ui) { changeslider(event, ui) }
        });

        changeslider();

    })

The function changeslider is really the glue that pulls it all together. It uses the DateRanger methods (display and fullStartDate) to retrieve the values used to update the page when the handles are changed.

$("#startlbl").text(cdv.display(sdateIndex));
$("#endlbl").text(cdv.display(edateIndex));


//These can be hidden fields and returned on postback
//For demonstraion purposes they are shown on the page.

$("#startlblday").text(cdv.fullStartDate(sdateIndex))
$("#endlblday").text(cdv.fullEndDate(edateIndex));

Notice that the variable cdv which is returned from the setCurrentDateView method is the object which contains the functions to display  and return appropriate indexes for the view selected. 

DateRanger.cs

The DateRanger object works in several phases.

Phase One - As the object is created, an array of datapoints is created and the array is validated for validity.

function appendYears(start_year, end_year) {
        //re-initialize
        datapointCollection = [];
        valid_years = [];
        valid_quarters = [];
        valid_months = [];

        while (start_year <= end_year) {
            datapointCollection.push(new initializeYear(start_year));
            start_year++;
        }
        validateCurrent(datapointCollection);
    }

 Phase Two - After Phase 1 is complete an array for each time frame is created

valid_year, valid_quarters and valid_months

function calcDateFrames() {
    //Fill in the valid_* arrays

    for (var y = 0; y < datapointCollection.length; y++) {
        if (datapointCollection[y].isValid)
            valid_years.push({
            StartMonth: 1,
            EndMonth: 12,
            year: datapointCollection[y].year });
        for (var q = 0; q < datapointCollection[y].quarters.length; q++) {
            if (datapointCollection[y].quarters[q].isValid)
                valid_quarters.push({
                StartMonth: q * 3 + 1,
                EndMonth: q * 3 + 3,
                year: datapointCollection[y].year,
                name: datapointCollection[y].quarters[q].name })
            for (var m = 0; m < datapointCollection[y].quarters[q].months.length; m++) {
                if (datapointCollection[y].quarters[q].months[m].isValid)
                    valid_months.push({
                StartMonth: q * 3 + m + 1,
                EndMonth: q * 3 + m + 1,
                year: datapointCollection[y].year,
                name: datapointCollection[y].quarters[q].months[m].name })
            }
        }
    }
}

Phase three - An object is returned which can be used by the changeslider event to report on the internal arrays for the selected date view (month, quarter, year. 

DateRanger.prototype.setCurrentDateView = function (strDateView) {
    var fdisplay = {};
    var startIndex = 0;
    var endIndex = 0;
    var selectedStartDate = {};
    var selectedEndDate = {};

    switch (strDateView) {
        case 'Month':
            fdisplay = function (index) { return valid_months[index].name + '/' + valid_months[index].year; };
            selectedStartDate = function (index) { return moment().year(valid_months[index].year).month(valid_months[index].StartMonth - 1).startOf('month').format("M/D/YYYY"); };
            selectedEndDate = function (index) { return moment().year(valid_months[index].year).month(valid_months[index].EndMonth - 1).endOf('month').format("M/D/YYYY"); };
            //the number is simply a guess as to how large of a spread you want to start with.
            startIndex = valid_months.length - 7;
            endIndex = valid_months.length - 1;
            break;
        case 'Quarter':
            fdisplay = function (index) { return valid_quarters[index].year + '/' + valid_quarters[index].name; };
            selectedStartDate = function (index) { return moment().year(valid_quarters[index].year).month(valid_quarters[index].StartMonth - 1).startOf('month').format("M/D/YYYY"); };
            selectedEndDate = function (index) { return moment().year(valid_quarters[index].year).month(valid_quarters[index].EndMonth - 1).endOf('month').format("M/D/YYYY"); };
            //the number is simply a guess as to how large of a spread you want to start with.
            startIndex = valid_quarters.length - 3;
            endIndex = valid_quarters.length - 1;
            break;
        default:
            fdisplay = function (index) { return valid_years[index].year; };
            selectedStartDate = function (index) { return moment().year(valid_years[index].year).month(valid_years[index].StartMonth - 1).startOf('month').format("M/D/YYYY"); };
            selectedEndDate = function (index) { return moment().year(valid_years[index].year).month(valid_years[index].EndMonth - 1).endOf('month').format("M/D/YYYY"); };
            //the number is simply a guess as to how large of a spread you want to start with.
            startIndex = valid_years.length - 2;
            endIndex = valid_years.length - 1;
            break;
    }

 Finally the object returns the functions selected in setCurrentDateView back to the 'Glue code' in the html file.

    return {
        sIndex: startIndex,
        eIndex: endIndex,
        display: fdisplay,
        fullStartDate: selectedStartDate,
        fullEndDate: selectedEndDate
    };
};

return DateRanger;

Points of Interest 

The code requires a reference to moment.js which is used to determine the last day of each selection

I've included two files which can be added to any existing project to test.

    

1. TestSlider.html

a.      A simple html file which contains references to JavaScript and CSS files.

b.      Contains a div for the slider, drop down for the mode as well as several labels for the display of dates selected.

c.      JavaScript glue logic to attach the visual controls to the logic code.

2.      DateRanger.js

a.      Follows the Module Design pattern

b.      It is an Immediately-Invoked-Function-Expressions (IIFE) encapsulating local variables and functions and returning a number of items used by the glue logic to display the controls correctly.

c.      Contains the logic to implements the rules defined previously.

Code

The code is supplied as part of this article but additionally will be available on Github for latest and updates.

The code is available at:

https://github.com/polarissolutions/DateSlider

In Conclusion

Business may know what they need to be successful but may not know how to get there or have the vocabulary to express their desires. When that occurs, it is up to us as a developers to add that extra value which will help business meet and exceed their customers expectations. 

Hope this helps and feel free to use in your projects as well.

 

License

This article, along with any associated source code and files, is licensed under The MIT License

Share

About the Author

DotNetSteve
Software Developer (Senior) Polaris Solutions
United States United States
Steven Contos

Working in varied settings from small entrepreneurial companies to Fortune 500 companies. Skilled in analyzing client needs and developing solutions that are sound and effective.

Strong analytic capabilities with proven accomplishments in developing programs that exceed or meet stated goals, consistently work well, are easily maintained and fully documented. Versed in a number of SDLC technologies including Agile and Scrum, dedicated to deliver high quality software on time and on budget.

Experienced in helping companies and teams change their culture. Providing clear vision, asking tough questions of both developers and business, leading by example and building trust among all concerned.

Comments and Discussions

 
GeneralMy vote of 5 Pin
TheQuake6-Aug-18 4:36
memberTheQuake6-Aug-18 4:36 
GeneralRe: My vote of 5 Pin
DotNetSteve6-Aug-18 16:26
memberDotNetSteve6-Aug-18 16:26 
SuggestionNice - needs screenshots Pin
euan.kennedy5-Aug-18 13:55
membereuan.kennedy5-Aug-18 13:55 
GeneralRe: Nice - needs screenshots Pin
DotNetSteve6-Aug-18 7:49
memberDotNetSteve6-Aug-18 7:49 
GeneralRe: Nice - needs screenshots Pin
DotNetSteve6-Aug-18 16:26
memberDotNetSteve6-Aug-18 16:26 

General General    News News    Suggestion Suggestion    Question Question    Bug Bug    Answer Answer    Joke Joke    Praise Praise    Rant Rant    Admin Admin   

Use Ctrl+Left/Right to switch messages, Ctrl+Up/Down to switch threads, Ctrl+Shift+Left/Right to switch pages.

Article
Posted 4 Aug 2018

Tagged as

Stats

4.7K views
34 downloads
2 bookmarked