13 Replies Latest reply on Dec 5, 2011 12:35 PM by DonMitchinson

    How to limit mx:DateField to particular days rather than ranges.

    trevorisjustso Level 1

      Maybe I'm thick...or just new but I can't figure this out.

       

      DateField

       

      Instead of a range of dates using selectableRange, I want to to pass a list of possible Dates.

       

       

      instead of :  {rangeStart: new Date(2001, 4, 7), rangeEnd: new Date(2003, 5, 7)};

       

      I want  {new Date(2001, 4, 7), new Date(2001, 4, 17),new Date(2001, 5, 7),new Date(2001,5, 22)};

       

       

      I'm binding it to the result of a httpservice.

       

      Please help.

       

       

      Oh, I'm using Flash Builder 4.6

        • 1. Re: How to limit mx:DateField to particular days rather than ranges.
          Flex harUI Adobe Employee

          I think you want to use disabledRanges.  SelectableRange controls the dates you can navigate to.

          • 2. Re: How to limit mx:DateField to particular days rather than ranges.
            trevorisjustso Level 1

            Actually, I'm dealing with a set in which there aren't ranges but individual days.  And there are LOT.  And they are differnt days.

             

            I would like to be able to have a list of dates that I can include rather than trying to figure out every single day that isn't in my list, and calculating the ranges between them.  I'm not that smart!

            • 3. Re: How to limit mx:DateField to particular days rather than ranges.
              Flex harUI Adobe Employee

              The control doesn’t support that.  You will have to calculate the ranges or days you don’t want.

               

              Do your customers need to see the monthly calendar UI?  Otherwise just list the dates in a ComboBox.

              • 4. Re: How to limit mx:DateField to particular days rather than ranges.
                trevorisjustso Level 1

                Well, I'm using it so users can select a range in a chart.

                 

                So yea, it's sorta best to use a calendar UI.

                • 5. Re: How to limit mx:DateField to particular days rather than ranges.
                  Flex harUI Adobe Employee

                  Are you trying to just pick out Wednesdays or something like that?  There is a disabledDays property as well.  You might just use a custom renderer in a ComboBox that looks like a month.  Otherwise you’ll have to figure out the disabledRanges

                  • 6. Re: How to limit mx:DateField to particular days rather than ranges.
                    DonMitchinson Level 2

                    Is there an internal limit to the selectableRanges property? 

                    ** edited ** - you answered that above - only one range is allowed.

                     

                    I think you can load it selectedRanges from a file of dates - or build an array on the fly

                    using start/end as same day.

                     

                    The 4.6 Docs have an excellent example of using an XML dataset to fill the array.

                     

                    This property accepts an Array of objects as a parameter.

                    Each object in this array has two date Objects,       rangeStart and rangeEnd.     

                    The range of dates between each set of rangeStart and rangeEnd (inclusive) are selected.     

                    To select a single day, set both rangeStart and rangeEnd to the same date.

                     

                    I'm sure a variation of this will work for you.

                     

                    public function displayDates():void {
                        var dateRanges:Array = [];
                        for (var i:int=0; i<shows.show.length(); i++) { 
                            var cDate:Date = 
                            new Date(shows.show[i].showDate.toString());           
                            var cDateObject:Object = 
                            {rangeStart:cDate, rangeEnd:cDate};
                            dateRanges.push(cDateObject);
                        }
                        dc1.selectedRanges = dateRanges;
                    }           
                    

                     

                     

                    <fx:XML id="shows" format="e4x">
                    <data>
                        <show>
                           <showID>1</showID>
                        <showDate>02/28/2008</showDate>
                        <showTime>10:45am/11:15am</showTime>
                        </show>
                        <show>
                        <showID>2</showID>
                        <showDate>02/23/2008</showDate>
                        <showTime>7:00pm</showTime>
                        </show>
                    </data>
                    </fx:XML>
                    

                     

                    Message was edited by: DonMitchinson modify note to indicate correct property

                    • 7. Re: How to limit mx:DateField to particular days rather than ranges.
                      DonMitchinson Level 2

                      Could you display the valid dates in the 'selectedRanges' property

                      and then trap for and reject dates outside that array in the valueCommit event?

                       

                      The other way would be to load the 'selectableRange' start /end dates to match the

                      min/max of your possible dates - and then set the 'disabledRanges" array to dates

                      not in the possible array.

                       

                      Would be a good bit of coding to figure that out on the fly.

                      • 8. Re: How to limit mx:DateField to particular days rather than ranges.
                        trevorisjustso Level 1

                        Okay, so I have the list of dates coming in from my MySQL httpservice request.

                         

                        pseudocode:

                         

                        sort array of distinct dates ...

                         

                        for..each adate in array

                        {

                          range[] = (adate + one day, lastdate- oneday)

                        lastdate = adate;

                         

                        }

                         

                         

                        is that how I would construct such a monster?    

                        • 9. Re: How to limit mx:DateField to particular days rather than ranges.
                          DonMitchinson Level 2

                          Pseudo code is a start...

                          Hard to know exactly without seeing how you return your data from the URL - assume it's PHP/MySQL??

                           

                          If it's just one line per date, you can setup your HttpService as resultFormat array - which it looks like you want to do above.

                          Setting up HttpService info at http://help.adobe.com/en_US/FlashPlatform/reference/actionscript/3/mx/rpc/http/mxml/HTTPSe rvice.html

                           

                          Assuming you're HttpService is returning the SORTED dates you want to allow... I would try something like this...

                           

                          Untested code + pseudo code...

                           

                          private static const msPerDay:int = 1000 * 60 * 60 * 24;
                          
                          private var arrValidDatesFromHttpArray = [];
                          [Bindable] private var validDateRangeObject:Object;
                          [Bindable] private var arrDisabledDates:Array = [];
                          
                          var datFirstDate:Date;
                          var datLastDate:Date;
                          var datDisableDate:Date;
                          
                          var disableDateObject:Object;
                          
                          arrDisabledDates.length = 0;
                          datFirstDate = new Date(arrValidDatesFromHttpArray[0]);
                          datLastDate = new Date(arrValidDatesFromHttpArray[arrValidDatesFromHttpArray.length-1]);
                          
                          // Assign Selectable Range to DateChooser control
                          validDateRangeObject = {rangeStart:datFirstDate, rangeEnd:datLastDate};
                          yourDateTimeChooserID.selectableRange = validDateRangeObject; // Object - can only define one range
                          
                          // Start looking for missing days to disable
                          datFirstDate = datFirstDate.getTime() + msPerDay; // Get next date to start checking 
                          
                          arrDisabledDates.length = 0; // Reset array 
                          for (var datDisableDate=datFirstDate; ObjectUtil.dateCompare(datDisableDate, datLastDate) == 0; datDisableDate = datDisableDate.getTime() + msPerDay) {
                               // use array filterFunction to loook for datDisableDate
                              // if array.length != 0 then
                             // add to disabled range - set startDate and endDate to same day
                             disableDateObject = {rangeStart:datDisableDate, rangeEnd:datDisableDate};
                             arrDisabledDates.push(disableDateObject);
                          }
                          
                          if (arrDisabledDates.length != 0) {
                               // Assign Disabled Dates range to DateChooser control
                               yourDateChooserControlID.disabledRanges = arrDisabledDates;
                          }
                          

                          Let me know how it goes - and what final product looks like.

                          I have to do something similar shortly

                           

                          Don

                           

                          Message was edited by: DonMitchinson Modified the date comparison logic to use mx.utils.ObjectUtil.dateCompare function

                          • 10. Re: How to limit mx:DateField to particular days rather than ranges.
                            DonMitchinson Level 2

                            Okay - here you go. A real working example of setting selectableRange and disabledRanges for a DateChooser control

                            using a HTTPService loader.

                             

                            I needed this as much as you, so I decided to see how many errors were in my pseudo code.

                             

                            This is a working example that I load from a HTTPService - on my server I created a text file of 50 random

                            dates in text format. So you'll obviously have to handle the xml case if you're dumping your data differently.

                            Just change the HTTPService resultFormat to match your format and then change the resultHandler code to load your XML into the date array.

                             

                             

                            <?xml version="1.0" encoding="utf-8"?>
                            <s:WindowedApplication xmlns:fx="http://ns.adobe.com/mxml/2009" 
                                                   xmlns:s="library://ns.adobe.com/flex/spark" 
                                                   xmlns:mx="library://ns.adobe.com/flex/mx"
                                                   creationComplete="sampleDates.send();">
                            
                                <s:layout>
                                    <s:BasicLayout/>
                                </s:layout>
                            
                                <fx:Script>
                                    <![CDATA[
                                        import mx.collections.ArrayCollection;
                                        import mx.controls.Alert;
                                        import mx.events.FlexEvent;
                                        import mx.rpc.events.ResultEvent;
                                        import mx.utils.ObjectUtil;
                            
                                        private static const msPerDay:Number = 1000 * 60 * 60 * 24; // Number of milliseconds in one day
                                        private var datCheckDate:Date;
                            
                                        private var arrValidDatesFromHttp:ArrayCollection;
                            
                                        [Bindable] 
                                        private var validDateRangeObject:Object;
                            
                                        [Bindable] 
                                        private var arrDisabledDates:Array = [];
                            
                                        // Load Date array from remote text file
                                        protected function sampleDates_resultHandler(event:ResultEvent):void
                                        {
                                            if (event.result != null) {
                                                var strListOfDates:String = event.result.toString();
                                                trace('List of Dates: \n: ' + strListOfDates);
                                                // Create ArrayCollection from Array of dates
                                                arrValidDatesFromHttp = new ArrayCollection(strListOfDates.split('\n'));
                            
                                                if (arrValidDatesFromHttp.length > 0) {
                                                    Alert.show('Number of Dates Loaded:' + arrValidDatesFromHttp.length.toString());
                                                    loadDisabledDates();
                                                } else {
                                                    Alert.show('No Dates Loaded');                        
                                                }
                            
                                            }
                                        }
                            
                                        // Filter by Date - must be exact match
                                        private function filterByDate(item:Object):Boolean
                                        {
                                            return (ObjectUtil.dateCompare(datCheckDate, new Date(item)) == 0);
                                        }
                            
                                      // Hacked function to handle server Daylight Savings glitches
                                      private function getNextDay(currentDate:Date):Date {
                                          var nextDay:Date;
                                          nextDay = new Date(new Date(currentDate.fullYearUTC, currentDate.monthUTC, currentDate.dateUTC,0,0,0).time + msPerDay);
                                          if (nextDay.hours == 23) {
                                              // increment to next day again - midnight
                                              nextDay = new Date(new Date(nextDay.fullYearUTC, nextDay.monthUTC, nextDay.dateUTC,0,0,0).time + msPerHour);
                                          } else if (nextDay.hours == 1) {
                                              // set to midnight
                                              nextDay = new Date(new Date(nextDay.fullYearUTC, nextDay.monthUTC, nextDay.dateUTC,0,0,0).time - msPerHour);
                                          }
                            
                                          return nextDay;
                                      }
                            
                                        // Load Disable Dates range
                                        private function loadDisabledDates():void {
                                            var datFirstDate:Date;
                                            var datLastDate:Date;
                                            var datPrevious:Date;                
                                            var datDisableDate:Date;
                            
                                            var newDateInMilliseconds:Number;
                                            var disableDateObject:Object;
                                            var dateNotFound:Boolean    = false;
                            
                                            var intCompare:int;
                            
                                            arrDisabledDates.length = 0;
                                            datFirstDate = new Date(arrValidDatesFromHttp[0]);
                                            datLastDate = new Date(arrValidDatesFromHttp[arrValidDatesFromHttp.length-1]);
                            
                                            // Assign Selectable Range to DateChooser control
                                            validDateRangeObject = {rangeStart:datFirstDate, rangeEnd:datLastDate};
                                            yourDateTimeChooserID.selectableRange = validDateRangeObject; // Object - can only define one range
                            
                                            // Assign Filter Function to find match by date
                                            arrValidDatesFromHttp.filterFunction = filterByDate;
                            
                                            // Start looking for missing days to disable
                                            for (datCheckDate=datFirstDate;  ObjectUtil.dateCompare(datCheckDate, datLastDate) == -1; datCheckDate = getNextDay(datCheckDate)) {
                            
                                                // Reset filter 
                                                arrValidDatesFromHttp.refresh();                    
                            
                                                // If we find no match then date must be disabled
                                                dateNotFound = (arrValidDatesFromHttp.length == 0);
                            
                                                if (dateNotFound) {
                                                    datDisableDate = datCheckDate; 
                                                    trace('==> Disabling Date: ' + datDisableDate);
                                                    disableDateObject = {rangeStart:datDisableDate, rangeEnd:datDisableDate};
                                                    arrDisabledDates.push(disableDateObject);
                                                }
                            
                                            }
                            
                                            if (arrDisabledDates.length != 0) {
                                                // Assign Disabled Dates range to DateChooser control
                                                yourDateTimeChooserID.disabledRanges = arrDisabledDates;
                                            }                
                                        }
                                    ]]>
                                </fx:Script>
                            
                                <fx:Declarations>
                                    <!-- Load Random Dates from HTTPService in cretaionComplete event of WindowedApplication -->
                                    <!-- (50 random dates from Sept to Dec 2011) -->
                            
                                    <mx:HTTPService id="sampleDates" url="http://www.public-knowledge.com/test/RandomDates.txt" useProxy="false" 
                                                    resultFormat="text" result="sampleDates_resultHandler(event)" />
                            
                                </fx:Declarations>
                            
                                <s:TitleWindow x="107" y="81" width="663" height="327" title="Testing Dates">
                                    <mx:DateChooser id="yourDateTimeChooserID" x="175" y="49" width="298" height="205"/>
                                </s:TitleWindow>
                            
                            </s:WindowedApplication>
                            

                             

                            If you or anyone else reading this let me know.

                            Also - would love to see some fine tuning of my hacks to get this to work.

                             

                            Look forward to comments and suggestions

                             

                            P.S. Anyone else want to generate the own list of random dates, the site I used was http://www.random.org/calendar-dates/

                             

                            My url in the sample code may not live forever so I'd advise creating your own server file

                             

                            Also - I've uploaded sample online project swf with view source enabled - give it 5 secs or so to load

                            http://www.public-knowledge.com/test/dateTest.html

                            Note that the random allowable dates I loaded were from Sept - Dec 2011 - so all other months are disabled automatically

                             

                             

                             

                            Message was edited by: DonMitchinson  Added link to website to generate list of random dates

                             

                            Message was edited by: DonMitchinson Hacked getNextDay function to handle servers that enforce Daylight Savings Time

                            • 11. Re: How to limit mx:DateField to particular days rather than ranges.
                              trevorisjustso Level 1

                              wow.  okay.

                               

                               

                              I'll try this out.  For reference sake...this is the style of  xml returned by the httpservice I'm using.

                               

                              <data>

                              <result id="1">

                                        <date>2011-09-19 17:01:20</date>

                                        <mood>2</mood>

                                        <anxiety>1</anxiety>

                                        <concentration>3</concentration>

                                        <fatigue>1</fatigue>

                              </result>

                              <result id="2">

                                        <date>2011-09-29 17:01:20</date>

                                        <mood>4</mood>

                                        <anxiety>3</anxiety>

                                        <concentration>1</concentration>

                                        <fatigue>2</fatigue>

                              </result>

                              <result id="3">

                                        <date>2011-10-01 17:01:20</date>

                                        <mood>2</mood>

                                        <anxiety>1</anxiety>

                                        <concentration>3</concentration>

                                        <fatigue>1</fatigue>

                              </result>

                              <result id="4">

                                        <date>2011-10-03 17:01:20</date>

                                        <mood>3</mood>

                                        <anxiety>3</anxiety>

                                        <concentration>3</concentration>

                                        <fatigue>3</fatigue>

                              </result>

                               

                              etc....

                               

                              </data>

                              • 12. Re: How to limit mx:DateField to particular days rather than ranges.
                                DonMitchinson Level 2

                                Excellent - let me know...

                                 

                                I haven't used XML from HttpService but I believe it's the default format (or specify "e4x" to make sure)

                                 

                                And I believe XMLListCollection can be used interchangeably with ArrayCollection - but like I said,

                                I haven't used it that way.

                                 

                                You can try something like this - but you most likely will have to swap out my ArrayCollection variables for XMLListCollection

                                 

                                I'll let you play - but interested if you get something to work - please post your code.

                                 

                                <?xml version="1.0" encoding="utf-8"?>
                                private var xmlListColl:XMLListCollection;
                                
                                <mx:HTTPService id="httpServiceID" url="{XMLDataFileLocation}" result="httpService_result()" resultFormat="e4x"/>
                                
                                private function httpService_result(evt:ResultEvent):void 
                                {
                                 var xmlList:XMLList = XML(evt.result).data.result; // where <data? is top node, <result> is repeating node
                                 xmlListColl = new XMLListCollection(xmlList);
                                }
                                
                                • 13. Re: How to limit mx:DateField to particular days rather than ranges.
                                  DonMitchinson Level 2

                                  Note that I just edited the getNextDay function to hack a fix for

                                  when servers force Daylight Savings Time changes.

                                  Original code post modified.

                                   

                                  If left as is, it was skipping a day whenever Daylight Savings occurred

                                   

                                  Don