AdobeStock_455007340

Programmatically Changing Flash Form Calendar Selectable Ranges

The Flash Forms calendar controls can restrict selectable date ranges. Fixes dates can be specified using the startRange and endRange attributes, but what if you need to programmatically change the ranges at runtime? The following example does just that, it uses two calendar controls to prompt for start and end dates, and uses a couple of lines of ActionScript to ensure that the end date cannot be before the start date.

var dtRangeStart=new Date(calStart.selectedDate);
calEnd.selectableRange={rangeStart: dtRangeStart};




Start Date:



End Date:




A live example can be viewed at http://www.forta.com/misc/flashforms/calendarrange.cfm.

28 responses to “Programmatically Changing Flash Form Calendar Selectable Ranges”

  1. PaulH Avatar
    PaulH

    no fair. you get to use new Date().

  2. jerry Avatar
    jerry

    On start up, the "end date" calendar doesn’t gray out the dates. They do gray out if you click on the "start calendar". Is there a way to make this happen when the page first loads?

  3. Reto Aeberli Avatar
    Reto Aeberli

    Unfortunally the this code works not with the limited flex version used in Blackstone. The use of new is not allowed in this version.

  4. Ben Forta Avatar
    Ben Forta

    Paul, Reto, have you tried it? I ran it under straight CFMX7, no Flex involved.

  5. Reto Aeberli Avatar
    Reto Aeberli

    Ok, you are right the example works. But if cfinput type="datefield" is used instead cfcalendar cf throws this error message
    Illegal usage of actionscript.
    The following actionscript commands are not allowed: "import, new, delete, createChild, loadmovie, duplicateMovieClip, AttachMovie, registerclass, createTextField, __proto__".
    It would make sense to use the same script with the datefield too, not?

  6. Reto Aeberli Avatar
    Reto Aeberli

    I can’t belife!!! Within the cfcalendar tag is no limited action script. LoadMovie and all the other stuff is allowed there.
    <cfsavecontent variable="test">
    loadMovie(‘http://livedocs.macromedia.com/flash/Samples/AccessibleApplications/AccessibleApplications.swf’, here);
    </cfsavecontent>
    <cfform format="flash" width="800" height="650">
    <cfformgroup type="horizontal">
    <cfformgroup type="vertical">
    <cfformitem type="text">End Date:</cfformitem>
    <cfcalendar name="calEnd" onchange="#test#">
    </cfformgroup>
    </cfformgroup>
    <cfinput type="button" name="here">
    </cfform>
    Best Regards,
    Reto

  7. Ben Forta Avatar
    Ben Forta

    I don’t know if it a bug or a feature, I wrote it without thinking much about it and it just worked. 😉

  8. Greg Avatar
    Greg

    After you click on a date in the Start Date calendar and then move ahead a month the date where today is on the End Date calendar is not showing until you click it..
    For example.. Click on the March 31st for Start Date. On the End Date calendar, move ahead to April and you’ll notice that the 26th is gone. Follow this through the calendar and you’ll see it happens for every month.

  9. dorgan Avatar
    dorgan

    I am noticing that but i am noticingthat it is not the 26th its whatever the current value is for the month such as today is the 29th so the 29th is not showing for the rest of the months

  10. Britt Avatar
    Britt

    Can’t get the flash cal to load. It stops at 40%. Tried on both IE and FireFox.

  11. Steve Walker Avatar
    Steve Walker

    With regard to the calendar oddity, it appears to be related to the location on the calendar of the highlighted current date. Today is first day, second week and therefore all future first day, second week dates want to be highlighted. This causes the font colors to be inverted – they appear to be missing. Cool "feature".

  12. pim Avatar
    pim

    I had the same surprise, using ‘new Date()’ and noticing afterwards:
    http://cfpim.blogspot.com/2005/04/clock-timer-in-flash-cfform-opening.html
    Freedom for actionscript 😀
    //Pim;

  13. Kit Avatar
    Kit

    can this code be modify and use with "datefield" within a form? I would like to gray out anydays that before today??

  14. jurli Avatar
    jurli

    Hello Ben
    How can i change also a previous set "endrange" (is setting from database) for the "calEnd"
    in the same function with setRangeStart?
    The problem is: if i decrease the "calStart" at runtime the value of "calEnd" persists restrict the range to the previous set "endrange".
    And i can not select the new lower range with the "calEnd".
    I hope you understand my bad english.
    A little sample with a bad syntax:
    var dtRangeStart=new Date(calStart.selectedDate);
    calEnd.selectableRange={rangeStart: dtRangeStart};
    !! calEnd.endrange ={rangeStart: dtRangeStart}; !!
    thanks for a little help
    Best Regards, jurli

  15. David I. Walsh Avatar
    David I. Walsh

    Will this bug/feature be changed in future versions of ColdFusion? I’d like to use something similar in a production environment.

  16. Reto Avatar
    Reto

    Hi David,
    Depends what do you like to do. To achive the result of the Sample from Ben you don’t need to use the restricted keyword new. It works perfectly with only line:
    <cfsavecontent variable="setRangeStart">
    calEnd.selectableRange={rangeStart: calStart.selectedDate};
    </cfsavecontent>

  17. David Walsh Avatar
    David Walsh

    What I’m trying to do is validate that a date entered from a datefield is greater than or equal to today’s date (without the page refreshing). To do this, I would have to create a new Date object in ActionScript. Is there some better way of doing this?

  18. DIGITALUnderworld Avatar
    DIGITALUnderworld

    Can this be used with the existing "dateFiled" type?

  19. Pete Avatar
    Pete

    Here is how to do the same with input type being "datefield"
    <cfinput type="datefield" name="calStart" onchange="{calEnd.selectableRange={rangeStart: calStart.selectedDate};}">
    <cfinput type="datefield" name="calEnd">

  20. JG4 Avatar
    JG4

    I made a slight change to force the users to select a Start and End date:
    <cfsavecontent variable="setRangeStart">
    var dtRangeStart=new Date(calStart.selectedDate);
    calEnd.selectableRange={rangeStart: dtRangeStart};
    calEnd.selectedDate = null;
    </cfsavecontent>
    …and each control has the required attribute set to true. Does anyone know how to modify the validation error message for a cfcalendar object? The "message" attribute is not available…it just says "Error in calEnd text"?
    Oh, and one more thing, someone asked asked about the illegal use of actionscript commands. I have found that if you do not have a space between the call and the "new" keyword (e.g. var dtRangeStart=new Date(calStart.selectedDate)), the compiler seems to ignore the new keyword. just food for thought. if you try the example above and put a space between (dtRangeStart = new), it will fail.

  21. Cathe Avatar
    Cathe

    Why does (#1) work to restrict date selection to current day and (#2) does not:
    Note: Same EXACT <cfsavecontent>:
    <cfsavecontent variable="setRangeStart">
    var dtRangeStart=new Date();
    calEnd.selectableRange={rangeStart: dtRangeStart};
    </cfsavecontent>
    (#1)
    <cfform format="flash" width="400" height="450">
    <cfformgroup type="horizontal">
    <cfformgroup type="vertical">
    <cfformitem type="text">End Date:</cfformitem>
    <cfcalendar name="calEnd" onChange="#setRangeStart#">
    </cfformgroup>
    </cfformgroup>
    </cfform>
    (#2)
    <cfsavecontent variable="setRangeStart">
    var dtRangeStart=new Date();
    calEnd.selectableRange={rangeStart: dtRangeStart};
    </cfsavecontent>
    <cfform format="flash" width="400" height="450">
    <cfformgroup type="horizontal" width="100%"
    label="Date:">
    <cfinput type="datefield" align="middle" border="1"
    name="calEnd" required="yes" readonly="no"
    onChange="#setRangeStart#">
    </cfformgroup>
    </cfform>

    (#2) results in error: Illegal usage of actionscript org.apache.oro.text.regex.Perl5Pattern@ (…etc)
    Is there some way to limit the datefield to not allow selection before the current date using only one datefield ???
    Much Appreciated.

  22. Simon Avatar
    Simon

    Thanks Ben and others for expanding on this topic.
    From the help above I was able to make a calendar where start and end dates restircted each other. The NOW date was also used as a restriction:
    <cfset datenow=dateformat(now(), ‘dd/mm/yyyy’) >
    <cfsavecontent variable="setRangeStart">
    calEnd.selectableRange={rangeStart: calStart.selectedDate};
    </cfsavecontent>
    <cfsavecontent variable="setRangeEnd">
    calStart.selectableRange={rangeEnd: calEnd.selectedDate};
    </cfsavecontent>
    <cfform format="flash" width="400" height="450" >
    <cfformgroup type="horizontal">
    <cfformgroup type="vertical">
    <cfformitem type="text">Start Date:</cfformitem>
    <cfcalendar endrange="#datenow#" name="calStart" onChange="#setRangeStart#">
    </cfformgroup>
    <cfformgroup type="vertical">
    <cfformitem type="text">End Date:</cfformitem>
    <cfcalendar endrange="#datenow#" name="calEnd" onchange="#setRangeEnd#">
    </cfformgroup>
    </cfformgroup>
    </cfform>
    I have been able to achieve similar with datefields however as there is no endrange attribute I did not know how to restict the now date:
    <cfform format="flash" width="400" height="450">
    <cfformgroup type="horizontal">
    <cfformgroup type="vertical">
    <cfformitem type="text">Start Date:</cfformitem>
    <cfinput type="datefield" name="calStart" mask="dd mmmm yyyy" onchange="{calEnd.selectableRange={rangeStart: calStart.selectedDate};}">
    </cfformgroup>
    <cfformgroup type="vertical">
    <cfformitem type="text">End Date:</cfformitem>
    <cfinput type="datefield" name="calEnd" mask="dd mmmm yyyy" onchange="{calStart.selectableRange={rangeEnd: calEnd.selectedDate};}">
    </cfformgroup>
    </cfformgroup>
    </cfform>
    Anyway thanks to those who have contributed above. If anyone knows how to restrict the NOW date in a datefield I would be greatful if you could post it.

  23. Jeff Avatar
    Jeff

    I modified this code a little bit more. There is only one small bug in it that I know of. Once a date is selected and then the user changes the year in the cfselect, the selectable ranges of the new dates are not showing up.
    Anybody have any ideas?
    <cfset thisyear = dateFormat(Now(),’YYYY’)>
    <!— Actionscript to handle the logic for the Datefields and select boxes —>
    <cfformitem type="script">
    function setRangeStart(Datename1:mx.controls.DateField, Datename2:mx.controls.DateField, EndSelect:mx.controls.ComboBox){
    var dtRangeStart = Datename1.selectedDate;
    Datename2.selectableRange = {rangeStart: dtRangeStart};
    Datename1.displayedYear = Number(EndSelect.selectedItem.data);
    _global.flag == 1;
    }
    function UpdateSelect(Datename1:mx.controls.DateField, select:mx.controls.ComboBox){
    <!— Jog the datefield to reduce the click lag on this update function —>
    Datename1.selectedDate = Datename1.selectedDate;
    <!— splice the string to find the year —>
    var year = Datename1.text.substr(6,4);
    <!—alert(‘date: ‘ +year+ ”, ‘Alert’);—>
    for(var i = 0; i< select.getLength(); i ++){
    select.selectedIndex = i;
    if(year == select.selectedItem.data){
    break; // this will terminate/exit the loop
    }
    }
    }
    function setStartYear(name:mx.controls.DateField, select:mx.controls.ComboBox){
    var StartDate = ”;
    if(name.text != ”){
    StartDate = name.text;
    name.selectedDate = null;
    StartDate = StartDate.substring(0, StartDate.length-4);
    StartDate += select.selectedItem.data;
    name.text = StartDate;
    }
    name.displayedYear = Number(select.selectedItem.data);
    name.selectedDate = StartDate;
    <!—alert(‘date: ‘ +Number(select.selectedItem.data)+ ‘ year: ‘ +name.displayedYear+ ”, ‘Alert’);—>
    }
    function Datelogic(StartSelect:mx.controls.ComboBox, EndSelect:mx.controls.ComboBox, Datename2:mx.controls.DateField){
    var Index = StartSelect.selectedIndex;
    for(var i = 0; i< StartSelect.getLength(); i ++){
    if(EndSelect.getLength() <= Index && i >= EndSelect.getLength()){
    EndSelect.addItem(selectYear1.getItemAt(i));
    }else{
    EndSelect.removeItemAt(Index+1)
    var year = Datename2.text.substr(6,4);
    if(year < EndSelect.selectedItem.data && _global.flag != 1){
    Datename2.selectedDate = null;
    Datename2.displayedYear = Number(EndSelect.selectedItem.data);
    <!—alert(‘second: ‘ +EndSelect.selectedItem.data+ ”, ‘Alert’);—>
    }
    }
    }
    _global.flag == 0;
    }
    function setRangeEnd(Datename1:mx.controls.DateField, Datename2:mx.controls.DateField, StartSelect:mx.controls.ComboBox){
    var dtRangeEnd = Datename1.selectedDate;
    Datename2.selectableRange = {rangeEnd: dtRangeEnd};
    Datename1.displayedYear = Number(StartSelect.selectedItem.data);
    _global.flag == 1;
    }
    </cfformitem>
    <cfformgroup type="horizontal" visible="yes" enabled="yes" style="marginLeft:-3;" >
    <cfinput type="datefield" name="ActAfterDate" width="125" label="After Date:" bind="#form.ActAfterDate#" onChange="setRangeStart(ActAfterDate, ActBeforeDate); UpdateSelect(ActAfterDate, selectYear1); Datelogic(selectYear1, selectYear2, ActBeforeDate);">
    <cfselect name="selectYear1" width="80" label="" onChange="setStartYear(ActAfterDate, selectYear1); Datelogic(selectYear1, selectYear2, ActBeforeDate); setRangeStart(ActAfterDate, ActBeforeDate);" onMouseDown="selectYear1.dropdownWidth = 90;">
    <cfoutput>
    <cfloop index="i" from="#thisyear#" to="2000" step="-1" >
    <option value="#i#"<cfif i eq thisyear>selected</cfif>>#i#</option>
    </cfloop>
    </cfoutput>
    </cfselect>
    <cfformitem type="spacer" height="1" />
    </cfformgroup>
    <cfformgroup type="horizontal" visible="yes" enabled="yes" style="marginLeft:-15;" >
    <cfinput type="datefield" name="ActBeforeDate" width="125" label="Before Date:" bind="#form.ActBeforeDate#" onChange="setRangeEnd(ActBeforeDate, ActAfterDate, selectYear1); UpdateSelect(ActBeforeDate, selectYear2);">
    <cfselect name="selectYear2" width="80" label="" onchange="setStartYear(ActBeforeDate, selectYear2);" onMouseDown="selectYear2.dropdownWidth = 90;">
    <cfoutput>
    <option value="#thisyear#"selected>#thisyear#</option>
    </cfoutput>
    </cfselect>
    </cfformgroup>

  24. Simon Avatar
    Simon

    Hi Jeff,
    I am interested to see your post in action. I have tried however get a 500 error. Is there any actionscript in your code that may cause this.
    Thanks Simon

  25. Kristin Avatar
    Kristin

    After taking bits from lots of blogs, including this one, I came up with the following manipulations of dateField inputs. I have two inputs, a Start Date and an End Date for a project. The Start Date must be at least today. The End Date must be within 6 months of the Start Date. I worked great, but when a user selected a Start Date in the current month that wasn’t today, in the End Date field, all future dates that were in the same position as today disappeared (as described in the posts above from 3/29/05 and 4/3/05). To get around that, I just altered when the End Date can be – I started it from today instead of from the Start Date. Hopefully the user won’t select a Start Date, select an End Date, then go back and change the Start Date to some time after the End Date.
    If anyone knows of a solution to that disappearance issue, I’d love to hear it!
    <!— http://www.forta.com/blog/index.cfm?mode=e&entry=1556 —>
    <cfform format="flash" name="myForm" width="300" height="300">
    <!— this restricts the startDate and endDate to begin at today —>
    <cfformgroup type="horizontal" visible="no" height="0">
    <cfinput type="datefield" name="firstAvailableDate" value="#dateAdd(‘d’,-1,now())#">
    </cfformgroup>
    <!— this restricts the endDate to within 6 months (86400000 seconds in 180 days) of startDate —>
    <cfformitem type="script">
    function setRange()
    {
    var dtRangeStartDate = startDate.selectedDate;
    var dt_num:Number = dtRangeStartDate.getTime();
    dt_num += 86400000 * 180;
    endDate.selectableRange = {rangeEnd: dt_num};
    }
    </cfformitem>
    <!— endDate.selectableRange = {rangeStart: dtRangeStartDate,rangeEnd: dt_num}; —>
    <!— when I set the endDate rangeStart to the startDate (and if startDate is after today but still in this month) it causes today’s position to "disappear" from future months. To get around it, I set the endDate disabledRanges rangeEnd to today (from firstAvailableDate) —>
    <cfinput type="datefield"
    name="startDate"
    label="Start Date"
    onChange="setRange()"
    onFocus="startDate.disabledRanges=[{rangeEnd:firstAvailableDate.selectedDate}];">
    <cfinput type="datefield"
    name="endDate"
    label="End Date"
    onFocus="endDate.disabledRanges=[{rangeEnd:firstAvailableDate.selectedDate}];">
    </cfform>

  26. Tim Avatar
    Tim

    hi
    Ben thanks again.
    Is there a disabledDays attribute?
    I only want users to be able to select a single day within the range
    Say for example a range of today – 2 weeks until today + 4 weeks but only be able to select a Monday date.
    thanks in advance.
    tim

  27. GiR Avatar
    GiR

    Hi Kristin,
    Do you know how to bind the startDate value to the endDate. For instance, if a user selects a week from now(), the user will be able to select days from now() and 6 months from the startDate. How can I disable the days before the startDate?
    I think my problem is:
    I need to bind the startDate value instead of the now() but I don’t know how I can do it, in the secondAvailableDate
    <cfformgroup type="horizontal" visible="no" height="0">
    <cfinput type="datefield" name="secondAvailableDate" value="#dateAdd(‘d’,0,now())#">
    </cfformgroup>
    <cfinput type="datefield"
    name="endDate"
    mask="dd/mm/yyyy"
    width="100"
    required="yes"
    message="End date is missing."
    onFocus="endDate.disabledRanges=[{rangeEnd:secondAvailableDate.selectedDate}];">
    Any ideas?

  28. Rebster Avatar
    Rebster

    Two date fields which you can select the date before today and not after.
    The second you can select the date after first date and not before.
    <cfformgroup type="horizontal" height="1">
    <cfinput type="datefield" name="firstAvailableDate" value="#dateAdd(‘d’, +1,now())#"
    </cfformgroup>
    <cfformgroup type="horizontal">
    <cfinput type="datefield" name="request_date" id="request_date" mask="mm/dd/yyyy" width="100" label=”Date Requested” value="#Todays#"
    onFocus="request_date.disabledRanges=[{rangeStart:firstAvailableDate.selectedDate}];" />
    <cfinput type="datefield" name="datedue" id="datedue" mask="mm/dd/yyyy" width="100" label=”Due Date” onFocus="datedue.disabledRanges=[{rangeEnd:request_date.selectedDate}];" />
    </cfformgroup type="horizontal" >
    Hope this helps.

Leave a Reply