Page 1 of 3 123 LastLast
Results 1 to 10 of 23

Thread: Ext.ux.picker.Time [timepickerfield]

  1. #1
    Sencha User
    Join Date
    Jul 2011
    Location
    The Netherlands
    Posts
    24
    Vote Rating
    6
      3  

    Default Ext.ux.picker.Time [timepickerfield]

    Timepicker for hours and minutes. The TimePickerField is derived from the Ext.field.DatePicker. So it inherits al default behavior. The value returned by timepicker is a full date object, with time portion.
    Here is a touch version of time picker:


    The picker:
    Code:
    /**
    * The picker with hours and minutes slots
    */
    Ext.define('Ext.ux.picker.Time', {
        extend:'Ext.picker.Picker',
        xtype:'timepicker',
    
    
        config:{
            /**
             * @cfg {Number} increment The number of minutes between each minute value in the list.
             * Defaults to: 5
             */
            increment:5,
    
    
            /**
             * @cfg {Number} start value of hours
             */
            minHours:0,
    
    
            /**
             * @cfg {Number} end value of hours.
             */
            maxHours:23,
    
    
            /**
             * @cfg {String} title to show above hour slot
             * Note: for titles to show set the {useTitle} config to true.
             */
            hoursTitle:'Hours',
    
    
            /**
             * @cfg {String} title to show above hour slot
             * Note: for this to show set the {useTitle} config to true.
             */
            minutesTitle:'Minutes',
    
    
            /**
             * @cfg {boolean} show/hide title headers.
             * Note: defaults to false (framework default 'Ext.picker.Picker')
             */
    
    
            slots: []
        },
    
    
        /**
         *
         * @param value
         * @param animated
         */
        setValue:function (value, animated) {
            var increment = this.getInitialConfig().increment,
                modulo;
    
    
            if (Ext.isDate(value)) {
                value = {
                    hours:value.getHours(),
                    minutes:value.getMinutes()
                };
            }
    
    
            //Round minutes
            modulo = value.minutes % increment;
            if (modulo > 0) {
                value.minutes = Math.round(value.minutes / increment) * increment;
            }
            this.callParent([value, animated]);
        },
    
    
        /**
         * @override
         * @returns {Date} A date object containing the selected hours and minutes. Year, month, day default to the current date..
         */
        getValue:function () {
            var value = this.callParent(arguments),
                date = new Date();
            value = new Date(date.getFullYear(), date.getMonth(), date.getDate(), value.hours, value.minutes);
            return value;
        },
    
    
        applySlots:function (slots) {
            var me = this,
                hours = me.createHoursSlot(),
                minutes = me.createMinutesSlot();
    
    
            return [hours, minutes];
        },
    
    
        createHoursSlot:function () {
            var me = this,
                initialConfig = me.getInitialConfig(),
                title = initialConfig.hoursTitle ,
                minHours = initialConfig.minHours,
                maxHours = initialConfig.maxHours,
                hours = [],
                slot;
    
    
            for (var i = minHours; i <= maxHours; i++) {
                var text = (i < 10) ? ('0' + i) : i; //Add leading zero
                hours.push({text:text, value:i});
            }
    
    
            slot = {
                name:'hours',
                align:'center',
                title:title,
                data:hours,
                flex:1
            };
    
    
            return slot;
        },
    
    
        createMinutesSlot:function () {
            var me = this,
                initialConfig = me.getInitialConfig(),
                title = initialConfig.minutesTitle ,
                increment = initialConfig.increment,
                minutes = [],
                slot;
    
    
            for (var j = 0; j < 60; j += increment) {
                var text;
                text = (j < 10) ? ('0' + j) : j; //Add leading zero
                minutes.push({text:text, value:j});
            }
    
    
            slot = {
                name:'minutes',
                align:'center',
                title:title,
                data:minutes,
                flex:1
            };
            return slot;
        }
    });

    The picker text field (extends from the datepickerfield)
    Code:
    /**
    * TimePickerfield. Extends from datepickerfield
    */
    Ext.define('Ext.ux.field.TimePicker', {
        extend:'Ext.field.DatePicker',
        xtype:'timepickerfield',
    
    
        requires:['Ext.ux.picker.Time'],
    
    
        config:{
            dateFormat:'H:i', //Default format show time only
            picker:true
        },
    
    
        /**
         * @override
         * @param value
         * Source copied, small modification
         */
        applyValue:function (value) {
            if (!Ext.isDate(value) && !Ext.isObject(value)) {
                value = null;
            }
    
    
            // Begin modified section
            if (Ext.isObject(value)) {
                var date = new Date(),
                    year = value.year || date.getFullYear(), // Defaults to current year if year was not supplied etc..
                    month = value.month || date.getMonth(),
                    day = value.day || date.getDate();
    
    
                value = new Date(year, month, day, value.hours, value.minutes); //Added hour and minutes
            }
            // End modfied section!
            return value;
        },
    
    
        applyPicker:function (picker) {
            picker = Ext.factory(picker, 'Ext.ux.picker.Time');
            picker.setHidden(true); // Do not show picker on creeation
            Ext.Viewport.add(picker);
            return picker;
        },
    
    
        updatePicker:function (picker) {
            picker.on({
                scope:this,
                change:'onPickerChange',
                hide:'onPickerHide'
            });
            picker.setValue(this.getValue());
            return picker;
        }
    });

    Usage:
    Code:
    {
        xtype: 'timepickerfield',
        label: 'time',
        value: new Date(), // object also possible {hours:12, minutes:25},
        name: 'time',
        picker:{
            height:300
            minHours:9, //(optional)Selectable hours will be between 9-18
            maxHours:18 // (optional) These values default to 0-24
        }
    }

    Code:
    //* Notes:
    getValue() // will return a {Date} object
    getFormattedValue() //will return H:i (example16:40)
    That's all. Any thoughts?


    [EDIT]
    - Refactored picker code.
    - Implemented mithcell's comments
    Attached Images Attached Images
    Last edited by renato01; 26 Mar 2012 at 7:43 AM. Reason: added image, changed namespace

  2. #2
    Sencha - Sr Software Engineer mitchellsimoens's Avatar
    Join Date
    Mar 2007
    Location
    Gainesville, FL
    Posts
    39,556
    Vote Rating
    1272
      0  

    Default

    You should make picker a proper config of Ext.ux.picker.Time and use applyPicker method to do the Ext.factory to create the slot instead of doing it in getPicker and in updatePicker add the listener and set value.
    Mitchell Simoens @LikelyMitch
    Sencha Inc, Senior Software Engineer
    ________________
    Learn BBCode and use it! Checkout the CODE tag!

    Check out my GitHub, lots of nice things for Ext JS and Sencha Touch
    https://github.com/mitchellsimoens

  3. #3
    Sencha User
    Join Date
    Jul 2011
    Location
    The Netherlands
    Posts
    24
    Vote Rating
    6
      0  

    Default Update

    Took @mitchellsimoens comments and modified code.
    Although, one question to @mitchell:
    How would you do this part? The setHidden and then add to Viewport part?
    Otherwise the picker won't show or immediately show after you add to Viewport..


    Code:
    applyPicker:function (picker) {
        picker = Ext.factory(picker, 'Ext.ux.picker.Time');
        picker.setHidden(true); // Do not show picker on creeation
        Ext.Viewport.add(picker);
        return picker;
    }

    I think that's why the Ext.field.DatePicker does the creation of the picker inside the getPicker(), when its first called..

  4. #4
    Sencha User
    Join Date
    Dec 2011
    Posts
    21
    Vote Rating
    1
      1  

    Default

    Here's my attempt at the same notion, not sure i'm loving the input/output value format, but it works.
    Code:
    /**
     * @author RWeneck
     * 
     * Adapted from https://github.com/ghuntley/Ext.ux.touch.DateTimePicker
     * 
     */
    Ext.define('Application.view.TimePicker', {
    	extend : 'Ext.Picker',
    	xtype : 'timepicker',
    
    
    	config : {
    		/**
             * @cfg {String/Number} value The value to initialize the picker with
             * @accessor
             */
            value: "11:00 AM",
    		/**
    		 * @cfg {String} hourText
    		 * The label to show for the hour column. Defaults to 'Hour'.
    		 */
    		hourText : 'Hour',
    		/**
    		 * @cfg {String} minuteText
    		 * The label to show for the minute column. Defaults to 'Minute'.
    		 */
    		minuteText : 'Minute',
    		/**
    		 * @cfg {String} daynightText
    		 * The label to show for the daynight column. Defaults to 'AM/PM'.
    		 */
    		daynightText : 'AM/PM',
    		/**
    		 * @cfg {Array} slotOrder
    		 * An array of strings that specifies the order of the slots. Defaults to <tt>['hour', 'minute', 'daynight']</tt>.
    		 */
    		slotOrder : ['hour', 'minute', 'daynight']
    
    
    	},
    	// @private
    	initialize: function() {
    		var me = this;
    		
    		var hours = [], 
    			minutes = [], 
    			daynight = [], 
    			i;
    			
    		for( i = 1; i <= 12; i++) {
    			hours.push({
    				text : i,
    				value : i
    			});
    		}
    
    
    		for( i = 0; i < 60; i += 5) {
    			minutes.push({
    				text : i < 10 ? '0' + i : i,
    				value : i
    			});
    		}
    
    
    		daynight.push({
    			text : 'AM',
    			value : 'AM'
    		}, {
    			text : 'PM',
    			value : 'PM'
    		});
    
    
    		
    		var newSlots = [];
    		Ext.each(this.getSlotOrder(), function(item) {
    			newSlots.push(this.createSlot(item, hours, minutes, daynight));
    		}, this);
    		
    		this.setSlots(newSlots);
    		this.callParent(arguments);
    	},
    	createSlot : function(name, hours, minutes, daynight) {
    		switch (name) {
    			case 'hour':
    				return {
    					name : 'hour',
    					align : 'center',
    					data : hours,
    					title : this.getUseTitles() ? this.getHourText() : false,
    					flex : 2
    				};
    			case 'minute':
    				return {
    					name : 'minute',
    					align : 'center',
    					data : minutes,
    					title : this.getUseTitles() ? this.getMinuteText() : false,
    					flex : 2
    				};
    			case 'daynight':
    				return {
    					name : 'daynight',
    					align : 'center',
    					data : daynight,
    					title : this.getUseTitles() ? this.getDaynightText() : false,
    					flex : 2
    				};
    		}
    	},
    
    
    	/**
    	 * Takes a String or an object that represents time,
    	 * The object should contain the keys; hour, minute, daynight
    	 * or the string should be in the format of "11:00 AM"
    	 */
    	setValue : function(value, animated) {
    		if(!value){
    			value = {
    				hour : 11,
    				minute : 00,
    				daynight : "AM"
    			}
    		}
    		if(typeof value == "string"){
    			var hour, minute, daynight;
    			value = value.trim();
    			hour = value.substring(0, value.indexOf(":"));
    			minute = value.substring(value.indexOf(":")+1, value.indexOf(" "));
    			daynight = value.substring(value.indexOf(" ")+1);
    			
    			value = {
    				hour : hour,
    				minute : minute,
    				daynight : daynight
    			}
    		}
    		this.callParent(arguments);
    		
    		for(key in value) {
    			slot = this.child('[name=' + key + ']');
    			if(slot) {
    				if(key === 'hour' && value[key] > 12) {
    					daynightVal = 'PM';
    					value[key] -= 12;
    				}
    				slot.setValue(value[key], animated);
    			}
    		}
    		return this;
    	}
    });
    Can be used like so:
    Code:
    var picker = Ext.create('Application.view.TimePicker', {
    			useTitles : true,
    			value : "11:30 AM"
    		});
    		Ext.Viewport.add(picker);
    		picker.show();
    Screen Shot 2012-04-02 at 2.23.02 PM.png

  5. #5
    Sencha User
    Join Date
    Apr 2012
    Location
    Denmark
    Posts
    71
    Vote Rating
    1
      0  

    Default

    This looks great, but how do you add it to an app and use it?
    I'm using Sencha Touch 2 with the MVC-file structure and have read a bit about the Ext.Loader, but I still get
    Uncaught Error: [Ext.createByAlias] Cannot create an instance of unrecognized alias: widget.timepickerfield

  6. #6
    Sencha User
    Join Date
    Dec 2011
    Posts
    21
    Vote Rating
    1
      0  

    Default

    Create a TimePicker.js in your app/view folder. Change the Ext.define line to your applications name:
    PHP Code:
    Ext.define('YOURAPPLICATON.view.TimePicker', {... 
    Then instantiate it like:
    PHP Code:
    var picker Ext.create('YOURAPPLICATION.view.TimePicker', {            
                
    useTitles true,            
                
    value "11:30 AM"        
    });        
    Ext.Viewport.add(picker);        
    picker.show(); 
    This extends from datepicker, not datepickerfield, so you'll need to add it to the viewport and call show, though it wouldnt take much to assign it to a pickerfield's picker value.

  7. #7
    Sencha User
    Join Date
    Apr 2012
    Location
    Denmark
    Posts
    71
    Vote Rating
    1
      0  

    Default

    I was trying to implement @renato01 version as I need a 24-hour clock. and that makes use of Ext.ux-folders.

  8. #8
    Sencha User
    Join Date
    Jul 2011
    Location
    The Netherlands
    Posts
    24
    Vote Rating
    6
      1  

    Default

    Quote Originally Posted by hjeDK View Post
    This looks great, but how do you add it to an app and use it?
    I'm using Sencha Touch 2 with the MVC-file structure and have read a bit about the Ext.Loader, but I still get
    Uncaught Error: [Ext.createByAlias] Cannot create an instance of unrecognized alias: widget.timepickerfield
    It looks like the files didn't load correctly.
    Make sure the two files are in the correct folder:
    - ext/ux/picker/Time.js
    - ext/ux/field/TimePicker.js

    Add the requires to your code and make sure they load correctly:
    Code:
    requires:['Ext.ux.field.TimePicker']
    You may also need to configure the loader correctly.
    Add this before you init your application

    Code:
    Ext.Loader.setConfig({
        enabled: true,
        paths:{
            'Ext': '../../Scripts/ext' //This should be the url to your script folder..
        }
    });
    That should do it!

    Once you get that working, you can try this (better solution/more advanced):
    Rename all occurrences of 'Ext' to 'YourAppName' and put the files in a 'ux' folder. The 'ux' should be on the same level as 'controller' & 'view'.
    Example:
    Code:
    'Ext.ux.field.TimePicker' to > 'YOUAPPNAME.ux.field.TimePicker'
    'Ext.ux.picker.Picker' to > 'YOUAPPNAME.ux.picker.Time'
    - /ux/picker/Time.js
    - /ux/field/TimePicker.js

  9. #9
    Sencha User
    Join Date
    Apr 2012
    Location
    Denmark
    Posts
    71
    Vote Rating
    1
      0  

    Default

    Thanks now I made it to show up on the view, but the sheet won't show up when I click the field.
    I put the example code in as an item in a fieldset along with a datepicker and a selectfield

    EDIT: the sheet turned up behind my panel that I have made as a modal popup. Any idea how to solve that?

  10. #10
    Sencha User
    Join Date
    Jul 2011
    Location
    The Netherlands
    Posts
    24
    Vote Rating
    6
      0  

    Default

    That might be a problem.. Because the picker is itself modal..
    Maybe look into zIndex...

Page 1 of 3 123 LastLast

Tags for this Thread

Posting Permissions

  • You may not post new threads
  • You may not post replies
  • You may not post attachments
  • You may not edit your posts
  •