Home > APEX > Multiple Date Selector

Multiple Date Selector

I am currently working on a project using ApEx that requires the user to have the ability to select multiple dates. So I came up with this pretty cool modified monthly calendar to accomplish that task. And I thought I’d share it with everyone else.

First create a new page. On that page create a calendar based on the following query.

For the Calendar Attributes, the date column will be based on sysdate, and the display column will be based on dummy. This is just for sample purposes. In a real implementation, you would want to based this on a table with some meaningful dates.

Next we need a MultiSelect list box to store all the selections. Create a new region in the second column of the page and then create a MultiSelect Item in that region. I based my LOV on another query that returns no rows since this is just a demo with no initial date to populate. The query I used was

select dummy a, dummy b from dual where 1=0

I called my element P2_DATES and set the height to 25. When you are done, your page will look something like this…

null

.

Ok, now for the magic. We want to be able to select a day, have it populate the list on the right and also give a visual indication that we have selected it. We will need to slightly modify the calendar template so we can locate each individual calendar cell. ( Or if you want to, copy the existing template and then use and modify that. Just remember, if you do do that, you need to set the calendar on the page to use the new copied template. ) From the ApEx development you will see a list of all the templates being used on the page

null

Click on the calendar template and then select the monthly template. We need a way for the javascript that we will write to locate the specific <TD></TD> that is the individual date we click on. We will give each date cell a unique ID.

In the Weekday format section, modify the Day Open Format to include the following ID attribute:

<td class=”t13Day” valign=”top” id=”CELL#YYYY##MM##DD#”>

And add the same ID attribute to both the Today Open Format:

<td valign=”top” class=”t13Today” id=”CELL#YYYY##MM##DD#”>

and the Weekend Open Format.

<td valign=”top” class=”t13WeekendDay” id=”CELL#YYYY##MM##DD#”>

Note: I am using the default template #13. If you chose a different default template, then your class attribute will be different. The important thing is that you add the correct ID attribute to the <TD> tag.

Now all that is left is to add the javascript that does the real magic. Go back edit the page and in the page section, add the following javascript to the Header Text

<script>
var selectedColor = '#CC3333';

function addToSelectList( pList, pDisplay, pValue )
{
  var s = document.getElementById( pList );
  s.length++;
  s.options[s.length-1].text = pDisplay;
  s.options[s.length-1].value = pValue;
}

function removeFromSelectList( pList, pValue )
{
  var s = document.getElementById( pList );
  for ( i=0; i<s.length; i++ )
  {
    if ( s.options&#91;i&#93;.value == pValue )
    {
      s.remove(i);
      return;
    }
  }
}

function toggleEvent( pCell, pList, pDisplay, pValue )
{
  var cell = document.getElementById( pCell );
  if ( cell.style.backgroundColor == "" )
  {
    addToSelectList( pList, pDisplay, pValue );
    cell.style.backgroundColor = selectedColor;
  }
  else
  {
    removeFromSelectList( pList, pValue );
    cell.style.backgroundColor = null;
  }
}

</script>

 

Last step. We need a way to trigger the toggleEvent function. We will attach that to the calendar dates. For that, you will need to edit the Calendar Attributes and define the Day Link like this:

Click to get the full size image.

You are passing 4 parameters to the toggleEvent function. The first is the ID that we set up in the template, the second is the ApEx name of the multiselect list, the third is the display value in the list and the forth is the actual value that will be submitted from the list.

Now we are ready to test. Run the page and select any day

Now as you select the days, they turn red and the date is populated in the multiselect list. Select it again and it will toggle off.

I have set up a quick working demo here ( http://apex.oracle.com/pls/otn/f?p=19903:2 )

There is still much work to be done to make this a functional page. The submit processess need to be written to take the the dates from the select list and do something with them. You may also want to modify the query that the calendar is based on and prepopulate the calendar selected dates. But I will leave those exercises to the reader at home. (Boy did I hate it when my college professors said that in class.) I have actually done all of that but its a bit more than I wanted to blog about in my first post ( well second, my iPhone post was my first ). But if people are interested in enhancing this and have questions, just ask. And if enough people are interested, I will do a part 2.

Well I hope you found this useful. Check back as I will be adding more cool tips and tricks like this in the future.

Categories: APEX Tags: , , ,
  1. August 10, 2008 at 1:16 pm

    Christopher,

    welcome to the APEX blogging community!
    BTW, nice tip! Hope to read more from you in the future.

    Patrick

  2. Brian
    October 31, 2008 at 11:09 am

    Hi,
    The multi select calendar is great. If you have the enhanced version with submit process, I’d be really keen to see it.
    Cheers,
    Brian

  3. John Johur
    December 4, 2008 at 9:13 pm

    I’m also very interested in step 2. I personally would like to read from a table and populate the dates automatically. Use red for instance for certain days and green for others. I guess we’d have to have a column in the table which would mark each date as a specific “color”. Then use your date ui to mark also appropriate dates and colors and save them back to the table.
    I’m going to see if I can use your tips and play with this.
    thanks

  4. Christopher Beck
    December 6, 2008 at 4:39 pm

    I’ve tried, but its hard to come up with a simple generic solution to step 2 that translates well into a blog post. But if you have specific questions, just ask and I’ll do my best to help out.

  5. Thomas Bockert
    January 26, 2009 at 8:19 pm

    I’ve created a process to insert the data into a table, but I’m having one quirk. After selecting the dates and putting them into the multiple select list, you have to also then select them a 2nd time in the multiple select list before hitting create (submit). Is there a way to read in the values of a multiple select list without having to highlight them?

    Here is my process for those interested:

    declare
    v_dates_array HTMLDB_APPLICATION_GLOBAL.VC_ARR2;
    begin
    v_dates_array := HTMLDB_UTIL.STRING_TO_TABLE(:P34_TOPIC_DT);
    FOR i in 1..v_dates_array.count
    LOOP
    insert into ht_calendar(topic,topic_dt,notes)
    values (:P34_TOPIC,to_date(v_dates_array(i),’mm/dd/yyyy’),:P34_NOTES);
    END LOOP;
    commit;
    exception
    when others then
    rollback;
    End;

    • Christopher Beck
      February 26, 2009 at 9:54 pm

      What I have done is write a simple javascript function that will highlight all the values in that select list and then call it when the submit button is pressed.

      The script is

      function highlightAll(b)
      {
      var a = $x(b);
      for( var i=0; i<=a.length; i++ )
      a.options[i].selected = true;
      }

      I put that in the Header of the page.

      and then I change the submit button to be URL based and the URL is

      javascript:highlightAll( ‘SELECT_LIST_NAME’);doSubmit(‘BUTTON_NAME’);

      That will call the script then do the normal APEX button submit.

      Also, in your code you have

      *snip*

      commit:
      when others then
      rollback;

      *snip*

      Don’t commit nor rollback in your processes. Let APEX handle the state of the transaction. Otherwise you can wind up with some of your work committed and some rolledback and yet still have a successful completion of the processes.

      And NEVER, EVER use when others. If you don’t know the exact error that you encounter, then how do you know how to handle it? Just let it bubble up, let the transaction fail and let the APEX print the error message on the page.

      hope this helps.

      chris.

  6. Thomas Bockert
    January 29, 2009 at 4:04 pm

    Thanks for replying. It seems to work except for my button, it does the highlight just fine, but won’t submit the page. I also get an “Error on page” in the status bar after hitting the button, but it will highlight my selected values. Here is my syntax:

    javascript:highlightAll( ‘P34_TOPIC_DT’);doSubmit(‘CREATE’);

    If I take out the highlight and only do the submit, the submit will work.

    Also thanks for the tips on the commit & rollback. I didn’t know APEX would handle that automatically in a custom anonymous block process. Thought it only did it with the standard DML processes that do the checksum automatically.

  7. Pawel
    July 22, 2009 at 3:30 pm

    Hi Christopher,

    I found two small mistakes in your code (at least they show up in my latest IE browser:

    – I needed to modify the line in the script:
    from
    cell.style.backgroundColor = null;
    to
    cell.style.backgroundColor = ”;

    (otherwise the red background is not removed from the calendar when clicking on it again)

    I also needed to change the attributes
    from
    id=’CELL#YYYY##MM##DD#’
    instead of
    id=”CELL#YYYY##MM##DD#”

    (otherwise the Apex generates 2 double quotes which generates in an error).

    • Christopher Beck
      July 22, 2009 at 3:55 pm

      Thanks for the updates. I don’t use IE and never tested with it.

  8. Pawel
    July 23, 2009 at 8:18 am

    Christopher,

    I am very interested in the section 2 as well as the others 😉 I am not really familiar with JavaScript so I don’t realy understand the above code for storing the selected dates in a table 😦

    I am trying to come up with an application where users could simply click on a series of dates to mark their standby.

    What I did so far was the following:
    – I have created the table with 3 columns (ID, USER, STBY_DATE)
    – I have modified by Multi Select item and added database column STBY_DATE as source
    – I have added a Fetch Row process on my page to load a row from that table
    – I have added a Submit button with a database action INSERT
    – I have added a process Process DML for the same table

    However, when I execute that – nothing actually happens – the table remains empty (but there are no errors)

    Then I just added your function and modified the submit button (changed the ‘No target’ value to URL like this:
    javascript:highlightAll(‘P39_DATES’);doSubmit(‘SUBMIT’);

    However, when I now click on my Submit button I get an error:

    Message: ‘options[…]’ is null or not an object

    Any help would greatly be appriciated!

  9. Pawel
    July 23, 2009 at 1:01 pm

    I found the reason for the above error:
    It was simply the value of options[i] reaching null. After changing the line into:
    for( var i=1; i<=a.options.length-1; i++ )
    everything works fine.

    However, I am now struggeling with a way to mark the background colour of the days on loading the page and its contents from a table.

    • Christopher Beck
      July 23, 2009 at 5:18 pm

      Something like this should work. But you will have to include the jQuery libs.

      Not sure if you can do it with the default APEX javascript API easily. But I’m been messing around with jQuery lately and so this is how I’d to it today.

      The calendar query could look like:

      select theDate,
      ‘<div class=”hasDefaultValue”></div>’ || theText
      from dateTable

      and then in the footer Javascript you could have:

      $(“.hasDefaultValue”).parent().css( “backgroundColor”, selectedColor );

      Basically you need to “tag” those cells that have values ( adding the DIV tag ) and then reference them and then apply the background color on each ( using the cool and powerful one line of jQuery ).

      Hope this helps.

      chris.

      • Pawel
        July 29, 2009 at 12:53 pm

        Well, I know even less about jQuery (nothing basicaly). Therefore I was thinking more in terms of writing a JavaScript function which would just loop through all cells in search of a value from the table and then mark it red.
        For example I have added the following:

        function startEvent()
        {
        var a = ‘CELL20090705’;
        var cell = document.getElementById( a );
        cell.style.backgroundColor = selectedColor;
        }

        which markes one cell when you open the page. What I don’t know how to do is how to create a loop through all cells (since its a varchar) and how to read which cell should me marked from the underlying table?

        One other thing I noticed is that if you use your highlightAll function from above then each time you submit the page the values written to the table are doubled (since we always highligh all of the list – not just these which we recently marked but the ones coming from the table as well) 😦

        What I am looking for now is simply a way to read my dates table and correctly display it on the calendar (with setting the cells background).

      • Christopher Beck
        July 29, 2009 at 3:27 pm

        Well, you need to “tag” every cell that has a value so it can be identified in javascript. But since we can’t individually “tag” the TD cell, you need to set a DIV tag in the TD cell and then grab all those DIVs and then alter parent TD tag.
        That is what I showed in my previous response, but I see that some of the posting was missing because this editor stripped out the HTML. So lets try it again, and I will do it without jQuery.
        Make your query something like:
        select theDate,
        ‘<div class=”hasDefaultValue”></div>’ || theText
        from yourDateTable

        You need to and then your footer Javascript could be:
        <script>
        var d = $x_byClass( “hasDefaultValue” );
        for( var i=0; i<d.length; i++ )
        { d[i].parentNode.style.backgroundColor = selectedColor; }
        </script>

  1. August 10, 2008 at 12:36 pm

Leave a reply to Pawel Cancel reply