Copyright © 2008, Levyco Development, LLC. All rights are reserved.
Multiple Calendars With Linked Input Fields All Using A Single Widget...

Intro


The demo is intended to help users get the most out of the YUI Calendar control. The calendar control is a unique "widget" because it is actually a complete "window". That is, it is not an element added in the flow of your page -- it is specifically designed to be a "popup" element.


What most people find they want to do is have multiple calendar popups on a page, and furthermore, have "linked" user input fields for each input. In doing so, it is important to consider the efficiency of the solution, specifically, it is desirable to have a single calendar "widget".


This page will show you how to accomplish this goal, with a play-by-play commentary on the code that allows this to happen.


You may want to start by clicking the show demo button above so you can see what we're accomplishing, then you can follow along with the commentary as we show the code.


Some Background


Read the background page for additional details regarding the PHP code used on these pages. None of the PHP code is required to use or understand these demos.


So How's It Done?


The first thing we do is setup a container for the one calendar widget that will be created. The following little empty div is included in the body of the page:


<div id="popupCalContainer"></div>                            

Next we define a dialog that contains our demonstration inputs. It looks like this:



<div id="yfrmDemoContainer" class="YPANEL">

<div id="yfrmDemo">
    <div class="hd">Multiple Calendar Inputs/Single Widget...</div>
    <div class="bd">
        <table cellpadding="2">
            <tr>
                <td class="FORMLABEL">Birthday:</td>
                <td class="FORMFIELD"><?echo(makeInputItem("BDAY","date","",$NOW))?></td>
            </tr>
            <tr>
                <td class="FORMLABEL">High School Graduation:</td>
                <td class="FORMFIELD"><?echo(makeInputItem("HSGRAD","date","",$NOW))?></td>
            </tr>
            <tr>
                <td class="FORMLABEL">College Graduation:</td>
                <td class="FORMFIELD"><?echo(makeInputItem("COLGRAD","date","",$NOW))?></td>
            </tr>
            <tr>
                <td class="FORMLABEL">Wedding Anniversary:</td>
                <td class="FORMFIELD"><?echo(makeInputItem("ANNIV","date","",$NOW))?></td>
            </tr>
            <tr>
                <td class="FORMLABEL">Fell In Love With YUI:</td>
                <td class="FORMFIELD"><?echo(makeInputItem("YUI","date","",$NOW))?></td>
            </tr>
        </table>
    </div>
    <div class="ft"></div>
</div>
</div>

This is just a standard div for the most part that will be turned into a nice dialog by YUI. The only two unique things here are the outer "container" div with a class of YPANEL, and the PHP. YPANEL is a CSS rule that simply contains visibility:hidden. The PHP is simply a helper function that produces the drop-down list boxes that get linked to the calendar widget.


Here is how we tell YUI to make a pretty dialog/panel out of the div.


frmDemo = new YAHOO.widget.Panel("yfrmDemo", { modal:false, draggable:true, x:100, y:100, width:400, zIndex:10, underlay:"shadow", visible:false, fixedcenter:false, constraintoviewport:false, close:true } );
frmDemo.render();                            

Let's look at the actual data input fields and calender popup button. The PHP function makeInputItem is being told to generate a "date" input item. For example, the first call results in the following HTML:


<select name="BDAY_m" id="BDAY_m" size="1" class="FORMINPUTVAR" >
<option value="1" >1</option>
<option value="2" >2</option>
 :
<option value="12" >12</option>
</select>
/<select name="BDAY_d" id="BDAY_d" size="1" class="FORMINPUTVAR" >
<option value="1" >1</option>
<option value="2" >2</option>
 :
<option value="31" >31</option>
</select>
/<select name="BDAY_y" id="BDAY_y" size="1" class="FORMINPUTVAR" >
<option value="2001" >2001</option>
<option value="2002" >2002</option>
 :
<option value="2018" >2018</option>
</select>
<button id="BDAY_b" onclick="popupCalendar('BDAY_m','BDAY_d','BDAY_y','BDAY_b');return(false);"><img src="/images/t_calendar.gif"></button>                            

Now the real interesting stuff starts happening. The button that gets generated with the input fields calls the popupCalendar function when clicked. This function is in the global helper function script module included by the page (yuihelp.js).


var calInit = true;
var calObj;
var calElM;
var calElD;
var calElY;

function popupCalendar (elM, elD, elY, elBut) {

    if (!YAHOO.util.Dom.inDocument('popupCalContainer')) return;

    calElM = elM;
    calElD = elD;
    calElY = elY;

    var msel = getElement(elM);
    var dsel = getElement(elD);
    var ysel = getElement(elY);
    var m = msel.options[msel.selectedIndex].value;
    var d = dsel.options[dsel.selectedIndex].value;
    var y = ysel.options[ysel.selectedIndex].value;
    var my = m + '/' + y;
    var mdy = m + '/' + d + '/' + y;

    if (calInit) {
        calInit = false;
        calObj = new YAHOO.widget.Calendar ('popupCal', 'popupCalContainer', { title:'Select&nbsp;Date...', pageDate:my, selected:mdy, close:true });
        calObj.selectEvent.subscribe (popupCalendarHandler);
    }
    else {
        calObj.cfg.setProperty ('pageDate', my, false);
        calObj.cfg.setProperty ('selected', mdy, false);
    }

    var xy = YAHOO.util.Dom.getXY(elBut);
    xy[0] += 20;
    xy[1] += 10;
    calObj.render();
    calObj.show();
    YAHOO.util.Dom.setXY ('popupCalContainer', xy, false);

}

function popupCalendarHandler (type, args, obj) {

    var dates = args[0];
    var date = dates[0];
    setOptionByValue (getElement(calElM),date[1]);
    setOptionByValue (getElement(calElD),date[2]);
    setOptionByValue (getElement(calElY),date[0]);
    calObj.hide();

}                            

This function decides if a widget needs to be created, or if we can just reuse the one we already built. At the end of the function, the widget gets moved to be close to the button that was pressed. Note how the object is rendered and shown before the XY location is set. This is necessary or the calendar may (or may not) move to the desired location. Note how the function first tests to make sure that the target div is actually in the page before it does anything.


The popupCalendarHandler function gets called when a calendar selection is made, and it synchronizes the user input fields with the selected value and hides the popup. This could have just as easily been a text input field, but I prefer the drop downs. The fuction calls some additional functions in yuihelp.js:


function getElement (name) {
    return (YAHOO.util.Dom.get(name));
}

function getOptionIndex (list, value) {

    if (list) {

        var n = list.options.length;
        var i;
        var p = 0;

        for (i=0; i<n; i++) {
            if (list.options[i].value == value) return (i);
        }

    }

    return (0);

}

function setOptionByValue (list, value) {
    if (list) {
        list.selectedIndex = getOptionIndex(list,value);
    }
}                            

That's it! By modularizing your code and building reusable tools, you can generate some really sophisticated web applications with very little effort. A lot of what we looked at here is part of the global functions script (which should be taken out of the global namespace really), and are therefore not dealt with on a page-by-page basis. For example, here is the entire source code for this page (with this help commentary removed). Nice and short!



<?


    
////////////////////////////////////////////////////////////////////////////////////////////////////////////////
    //
    //      demos/calendar/multi_cals_on_a_page_help.php
    //      ============================================
    //
    //      this is the "help" page for multi cals on a page
    //
    //      COPYRIGHT (C) 2008, Levyco Development, LLC.  All Rights Are Reserved.
    //
    //      ver 1.0.0 2008-10-02 BLevy
    //
    ////////////////////////////////////////////////////////////////////////////////////////////////////////////////


    // master include

    
include_once("yuihelpglobal.php");

    
// set the YUI requirements

    
$YUI = array("container""button""calendar");

    
// draw the user interface

    
$UI->pageTop(""$YUI);

?>

    <div id="yfrmHelpContainer" class="YPANEL">
      <!-- COMMENTARY REMOVED BECAUSE IT IS NOT RELEVANT TO THE DEMO -->
    </div>

    <div id="yfrmDemoContainer" class="YPANEL">
    <div id="yfrmDemo">
        <div class="hd">Multiple Calendar Inputs/Single Widget...</div>
        <div class="bd">
            <table cellpadding="2">
                <tr>
                    <td class="FORMLABEL">Birthday:</td>
                    <td class="FORMFIELD"><?echo(makeInputItem("BDAY","date","",$NOW))?></td>
                </tr>
                <tr>
                    <td class="FORMLABEL">High School Graduation:</td>
                    <td class="FORMFIELD"><?echo(makeInputItem("HSGRAD","date","",$NOW))?></td>
                </tr>
                <tr>
                    <td class="FORMLABEL">College Graduation:</td>
                    <td class="FORMFIELD"><?echo(makeInputItem("COLGRAD","date","",$NOW))?></td>
                </tr>
                <tr>
                    <td class="FORMLABEL">Wedding Anniversary:</td>
                    <td class="FORMFIELD"><?echo(makeInputItem("ANNIV","date","",$NOW))?></td>
                </tr>
                <tr>
                    <td class="FORMLABEL">Fell In Love With YUI:</td>
                    <td class="FORMFIELD"><?echo(makeInputItem("YUI","date","",$NOW))?></td>
                </tr>
            </table>
        </div>
        <div class="ft"></div>
    </div>
    </div>

<? $UI->pageBottom(); ?>

<script type="text/javascript">
<!--

    var frmHelp;
    var frmDemo;

    function init () {

        frmHelp = new YAHOO.widget.Panel("yfrmHelp", { modal:false, draggable:true, x:20, y:75, width:740, zIndex:10, underlay:"shadow", visible:true, fixedcenter:false, constraintoviewport:false, close:false } );
        frmHelp.render();
        frmHelp.show();

        frmDemo = new YAHOO.widget.Panel("yfrmDemo", { modal:false, draggable:true, x:100, y:100, width:400, zIndex:10, underlay:"shadow", visible:false, fixedcenter:false, constraintoviewport:false, close:true } );
        frmDemo.render();

        YAHOO.util.Event.addListener("cmdShowDemo", "click", function(){frmDemo.show();});

    }

    YAHOO.util.Event.onDOMReady (init);

//-->
</script>

Multiple Calendar Inputs/Single Widget...
Birthday: //
High School Graduation: //
College Graduation: //
Wedding Anniversary: //
Fell In Love With YUI: //