A guide on transforming Jonatas Walker's TimePicker into a custom JavaScript class or a versatile jQuery plugin

I came across a timepicker solution on this Stack Overflow answer that I really liked. However, I encountered difficulties trying to implement it in a project where input elements are dynamically created. It seemed like the timepicker required specific handling of the object returned by the constructor. I wanted it to function more like the jQuery-UI datepicker, so I attempted to create a JavaScript class before diving into creating a jQuery plugin:

function MyTimePicker(inputelement) {
    // store the timepicker object
    this.mytimepicker = new TimePicker(inputelement);
    // display the selected time in the element
    this.mytimepicker.on('change', function (evt) {
        var value = (evt.hour || '00') + ':' + (evt.minute || '00');
        evt.element.value = value;
    });
}

I tried using this class on three different input elements:

var dummy1;
var dummy2;
var dummy3;
window.onload = function () {
    dummy1 = new MyTimePicker(jQuery('#time2').get(0));
    dummy2 = new MyTimePicker(jQuery('#time3').get(0));
    dummy3 = new MyTimePicker(jQuery('#time4').get(0));
};

Unfortunately, it didn't work as expected. The timepicker popup appeared when clicking on each input element, but the 'on(change)' event was never triggered, so the selected time was not displayed in the input field.

This could be due to my lack of experience with JavaScript objects or perhaps an issue with the timepicker itself.


Update: I made some improvements by setting up a proper prototype. Here is the complete code for standalone testing:

<!DOCTYPE html>
<html>
<head>
    <title>Timepicker class, standalone, by Jonatas Walker</title>
    <meta charset="utf-8" />
    <meta name="viewport" content="width=device-width, initial-scale=1" />
    <script src="https://ajax.googleapis.com/ajax/libs/jquery/1.12.1/jquery.min.js"></script>
    <link href="//cdn.jsdelivr.net/timepicker.js/latest/timepicker.min.css" rel="stylesheet">
    <script src="//cdn.jsdelivr.net/timepicker.js/latest/timepicker.min.js"></script>
</head>
<body>
    <div id="arrayoftimes">
        <input id="time2" type="time" placeholder="Time HH:MM"><br />
        <input id="time3" type="time" placeholder="Time HH:MM"><br />
        <input id="time4" type="time" placeholder="Time HH:MM"><br />
    </div>
    <script>
        // Javascript Class. this disturbs the above reference application of TimePicker. It probably is not re-entrant.
        //constructor
        function MyTimePicker(selector) {
            this.mytimepicker;
            this.init(selector);
        }
        //prototype
        MyTimePicker.prototype = {
            init: function (selector) {
                var inputelement = jQuery(selector).get(0);
                this.mytimepicker = new TimePicker(inputelement);
                // show picked time in the element
                this.mytimepicker.on('change', function (evt) {
                    var value = (evt.hour || '00') + ':' + (evt.minute || '00');
                    evt.element.value = value;
                });
            }
        };
    </script>
    <script>
        var dummy1;
        var dummy2;
        var dummy3;
        window.onload = function () {
            dummy1 = new MyTimePicker('#time2');
            dummy2 = new MyTimePicker('#time3');
            dummy3 = new MyTimePicker('#time4');
        };
    </script>
</body>
</html>

Now the first input element functions correctly, but the selected time value is being populated in all three input fields. The other two inputs trigger the timepicker dialog, but the chosen value doesn't appear.

In the browser console, after selecting a time, I noticed two errors from the timepicker.js file: TypeError: active is undefined.

This might suggest that the timepicker's internal code isn't re-entrant in nature?

Or maybe I'm misunderstanding something about object-oriented JavaScript?


Update:

I suspect there may be a bug in timepicker.js. I will update here once I identify and address it.

Answer №1

Thanks to the guidance of gforce301, I was able to devise a solution for transforming the timepicker into a jQuery plugin. The code includes test cases and functionalities as checkboxes to toggle inputs for the timepicker.

You can find the plugin implementation at the conclusion of this code snippet.

Functioning: Additional inputs with the timepicker can be added, and experimenting by selecting more checkboxes is encouraged.

Not Working: The removal of a timepicker from an input is currently not supported. If a checkbox is deselected, the associated input will not be included in the new target list passed to the setTarget() method, but the timepicker will persist on the deselected input.

<!DOCTYPE html>
<html>
    <head>
        <title>Test of Timepicker class, standalone, by Jonatas Walker</title>
        <meta charset="utf-8" />
        <meta name="viewport" content="width=device-width, initial-scale=1" />
        <script src="https://ajax.googleapis.com/ajax/libs/jquery/1.12.1/jquery.min.js"></script>
        <!--  source: https://github.com/jonataswalker/timepicker.js SO: https://stackoverflow.com/a/36758501/1845672 -->
        <link href="http://cdn.jsdelivr.net/timepicker.js/latest/timepicker.min.css" rel="stylesheet">
        <script src="http://cdn.jsdelivr.net/timepicker.js/latest/timepicker.min.js"></script>
        <style>
            .timepicker {background-color: yellow;}
        </style>
    </head>
    <body>
        <div id="arrayoftimes">
            Time 1
            <input type="checkbox" onclick="settimeclass(this, '#time1')" />
            <input id="time1" type="text" placeholder="Time HH:MM"/>
            <br />
            Time 2
            <input type="checkbox" onclick="settimeclass(this, '#time2')" />
            <input id="time2" type="text" placeholder="Time HH:MM"/>
            <br />
            Time 3
            <input type="checkbox" onclick="settimeclass(this, '#time3')" />
            <input id="time3" type="text" placeholder="Time HH:MM"/>
            <br />
            <br />
            IDs with timepicker: <span id='msg'></span>
        </div>
        <script> //this code is specific to this page
            // uncheck all checkboxes upon page load
            $('input:checkbox').prop('checked', false);
            $('input:text').val('');
            // adjust the timepicker class on each time input when (un)checking a checkbox
            function settimeclass(self, id){
                if ($(self).prop('checked')){
                    $(id).addClass('timepicker');
                }else{
                    $(id).removeClass('timepicker');
                }
                // initialize the timepicker jquery plugin
                $('.timepicker').timepicker();
            }
        </script>
        <script> // this code could be moved to a library
            // custom jquery plugin for Jonatas's timepicker
            (function ( $ ) {
                // create time picker object
                var _timepickerobj = new TimePicker([]);//([...], {lang:'en', theme:'dark'});
                // event handler for formatting the time
                _timepickerobj.on('change', function(evt) {              
                  var value = (evt.hour || '00') + ':' + (evt.minute || '00');
                  evt.element.value = value;
                });
                // define timepicker target using jquery selector
                $.fn.timepicker = function() {
                    var sel_array = this.toArray();
                    //_timepickerobj.target = [];// no effect
                    _timepickerobj.setTarget(sel_array);
                    // debugging: display time input ids with timepicker
                    var sel_ids = $.map(sel_array ,function(sel) {return sel.id;});
                    $('#msg').text(sel_ids);
                    return this;
                }
            }( jQuery ));
        </script>
    </body>
</html>

This plugin serves its purpose well in my project, although enhancements to support removing a timepicker from an input would be greatly appreciated.

Similar questions

If you have not found the answer to your question or you are interested in this topic, then look at other similar questions below or use the search

Looking to incorporate jQuery Form Wizard with mandatory radio button groups?

Currently, I am utilizing the jQuery Form Wizard plugin from The Code Mine website to transform a form into a wizard format. Myform consists of five pages, each containing approximately four radio buttons. It is crucial that at least one radio button on ea ...

A step-by-step guide on building a custom contact form using ReactJS and transmitting the data through an API with Express

In my quest to utilize ReactJS for building a contact form and seamlessly sending the data to my email address, I embarked on creating a contact form within my App.js file. import React, { Component } from 'react'; import axios from 'axios& ...

The JavaScript function on the specified /url page is not functioning properly following the execution of history.push(/url) on click

I have a JavaScript function that toggles the display of login password. However, when I redirect to the login page from another page using history.push(/login), the function does not work. It does work when I use (/login) in the href tag. How can I resolv ...

How can I adjust the vertical position of Material-UI Popper element using the popper.js library?

https://i.stack.imgur.com/ZUYa4.png Utilizing a material-ui (v 4.9.5) Popper for a pop-out menu similar to the one shown above has been my recent project. The anchorElement is set as the chosen ListItem on the left side. My goal is to have the Popper alig ...

Executing a controller method in AngularJS when redirecting a page

I am currently working on an app using Cordova/Phonegap, Ionic, and AngularJS. One challenge I am facing is trying to call a method from a controller inside my app when redirecting to another HTML page (secondPage.html). This particular method (secondMetho ...

Issue with unrecognized expression in JQuery when processing Ajax response

Recently, I implemented a JQuery Ajax Form on my website. $('#modal-body-sign-in').on('submit', '#sign-in', function(e) { e.preventDefault(); var data = $(this).serialize(); var url = $(this).attr(&apo ...

Exploring a different approach to utilizing Ant Design Table Columns and ColumnGroups

As per the demo on how Ant Design groups columns, tables from Ant Design are typically set up using the following structure, assuming that you have correctly predefined your columns and data: <Table columns={columns} dataSource={data} // .. ...

Is there a way to capture all ajax responses?

Is it possible to capture all responses from an ajax request, regardless of the library being used such as jQuery, prototype, or just the vanilla XMLHttpRequest object? I am looking for a way to append to any existing handler without removing it. Thank y ...

Switch between display modes by clicking using collections

I am trying to figure out how to create a function that will only show content for the specific element in which my button is located. Currently, when I click the button it shows content for all elements with the 'one' class, but I want it to dis ...

I need assistance in testing the component with the react query library as it requires a query client

I am encountering a specific issue while adding tests and need help to resolve it. I want to know how to set the query client inside the register page itself. Register.jsx --- Main page for user registration where I am attempting DOM testing. /* eslint ...

Unable to locate the accurate information

Every time I run the cycle, there should be a match with the specified parameters and the message "OK" should appear. However, I am always getting a result of "No". request( { url: 'http://localhost:5000/positions/get', metho ...

Bootstrap3 Remote Modal experiencing conflict due to Javascript

Utilizing a bootstrap modal to showcase various tasks with different content but the same format is my current goal. However, I am encountering an issue when attempting to make the textareas editable using JavaScript. The conflict arises when I open and cl ...

Explore one of the elements within a tuple

Can we simplify mapping a tuple element in TypeScript? I'm seeking an elegant way to abstract the following task const arr: [string, string][] = [['a', 'b'], ['c', 'd'], ['e', 'f']] const f ...

Customize URL based on selected button

My question may be a bit unclear, but I want to generate dynamic URLs that redirect users to specific pages based on the link clicked. For example: Parent page with links (a, b, c, x, y) User clicks on 'b' User is taken to a Node Page that play ...

Retrieve the route.js directory using Node.js

My server.js file is located in the directory: /dir1. To start the server, I use the command node server.js. In the directory /dir1/app/, I have my file named routes.js. I am trying to find out the directory path of the server.js file. However, I am unc ...

Place a new button at the bottom of the react-bootstrap-typeahead dropdown menu for additional functionality

Currently, I have successfully implemented the React Bootstrap Typeahead with the desired options which is a good start. Now, my next challenge is to integrate a custom button at the end of the dropdown list for performing a specific action that is not ne ...

What is the process for accessing a URL using a web browser and receiving a plain text file instead of HTML code?

Hello there! I've created a simple HTML file located at that can display your public IP address. If you take a look at the code of the page, you'll notice that it's just plain HTML - nothing fancy! However, I'm aiming for something mo ...

How to effectively refine a group query in Firestore to obtain specific results

My database structure is set up like this (simplified version): Collection: item_A -> Document: params = {someParameter: "value"} -> Document: user_01 -> Sub-collection: orders_item_A -> Document: order_AA ...

Tips for transforming a string into an object using AngularJS

Here is a string I'm working with: $scope.text = '"{\"firstName\":\"John\",\"age\":454 }"'; I am trying to convert it into a JavaScript object: $scope.tmp = {"firstName":"John","age":454 }; Please note: J ...

Vue fails to receive updates from Firestore until the page is manually refreshed

I set out to develop a task tracker app using Vue. As I neared completion of the project, I encountered an issue - when adding a new task, it would not change the reminder status unless I reloaded the page. Here is the code snippet from my Home.vue file: & ...