Reusing Magento’s calendar control

Featured Image

One of the cool things in Magento is that there is so many controls (widgets, blocks), etc. that you can reuse on the frontend or on the backend. One such control is the calendar control. Calendar control is mostly just used on the backend, aka “adminhtml” area. You can easily figure that one out if you do a quick search for a “Calendar.setup” string on “app/design” folder, in which case you would get several search results but all from “app/design/adminhtml/” folder.

So the question is how to get the calendar (from image above) to show on the frontend area? Easily, all you need is to include some CSS, few JavaScript’s, image and you are done. To make things more flexible, I wrote a little block class that does this for you.

class Inchoo_Module_Block_Calendar extends Mage_Core_Block_Template
{
    protected function _construct()
    {
        parent::_construct();
        $this->setTemplate('inchoo/calendar.phtml');
    }
 
    protected function _prepareLayout()
    {
        $this->_injectCalendarControlJsCSSInHTMLPageHead();
 
        return parent::_prepareLayout();        
    }    
 
    private function _injectCalendarControlJsCSSInHTMLPageHead()
    {
        $this->getLayout()->getBlock('head')->append(
            $this->getLayout()->createBlock(
                'Mage_Core_Block_Html_Calendar',
                'html_calendar',
                array('template' => 'page/js/calendar.phtml')
            )
        );
 
        $this->getLayout()->getBlock('head')
                ->addItem('js_css', 'calendar/calendar-win2k-1.css')
                ->addJs('calendar/calendar.js')
                ->addJs('calendar/calendar-setup.js');
 
        return $this;
    }
}

Please note that I placed this block class under the Inchoo/Module namespace, where you can easily make fully new YourCompany/Calendar extension and just put this in it, if you wish your entire extension just for calendar control.

Hopefully, _construct() method is clear to everyone in this case?! If not, then please skip this article entirely and jumo to the Magento Wiki 🙂

The core of the functionality here lies in the _injectCalendarControlJsCSSInHTMLPageHead() method which is called by _prepareLayout() method. If you study it closely you will see that _injectCalendarControlJsCSSInHTMLPageHead() adds the necessary CSS and JS to the head portion of the HTML page that gets rendered.

With this approach, all we need to do later in our XML layout files is just call our Calendar block like:

<block type="inchoo/calendar" name="inchoo.calendar" />

And finally the content of your app/design/frontedn/SOMEPACKAGE/SOMETHEME/template/inchoo/calendar.phtml file should look like:

<span>
    <img style="" title="Select Date" id="date_select_trig" class="v-middle" alt="" src="<?php echo $this->getSkinUrl("images/calendar.gif");?> "/>
    <input type="text" style="width: 120px;" class="input-text" value="" id="selected_date" name="selected_date"/>
    <script type="text/javascript">
    //<![CDATA[
        Calendar.setup({
            inputField: "selected_date",
            ifFormat: "%m/%e/%Y %H:%M:%S",
            showsTime: true,
            button: "date_select_trig",
            align: "Bl",
            singleClick : true
        });
    //]]>
    </script>
</span>

If all of the three files are in place then you should be able to see something like shown on image below.

Additionally, please keep in mind that this is really basic approach. You could do a bit more abstraction to it so that XML layout block accepts few more parameters that would be passed to a Calendar.php block class, like show a bit different calendar, do a bit different format pickup, etc. so that you can truly reuse the same control in various ways.

P.S. If Magento is having trouble loading calendar/calendar.js, calendar/calendar-setup.js, calendar/calendar-win2k-1.css then try doing a seach on entire installation and moving them to your theme then modify the addItem, addJs in your Calendar.php block class.

Hope this was helpful.


10 comments

  1. Can we add two buttons in Calendar.setup({ .
    I want to display a calendar on textbox as well as on Calendar icon click. How to do this?

  2. Hi,

    Above code disables all the date. So, I changed it a bit and its working for me now.

    //getId() . ‘”,
    ifFormat : “‘ . $displayFormat . ‘”,
    showsTime : “‘ . ($this->getTime() ? ‘true’ : ‘false’) . ‘”,
    button : “‘ . $this->getId() . ‘_trig”,
    align : “Bl”,
    singleClick : true,
    disableFunc: function(date) {
    var now= new Date();
    if(date.getFullYear() < now.getFullYear()) { return true; }
    if(date.getFullYear() == now.getFullYear()) { if(date.getMonth() < now.getMonth()) { return true; } }
    if(date.getMonth() == now.getMonth()) { if(date.getDate() < now.getDate()) { return true; } }
    },
    }';

  3. Use the folowing to disable the previous dates:

    <script type="text/javascript">
     Calendar.setup({
            inputField : '_dob',
            ifFormat : '%m/%e/%y',
            button : '_dob_trig',
            align : 'Bl',
            singleClick : true,
            disableFunc: function(date) {
              var now= new Date();
            if(date.getFullYear()<now.getFullYear())
            {
                return true;
            }
            if(date.getFullYear()==now.getFullYear())
            {
                if(date.getMonth()<now.getMonth())
                {
                    return true;
                }
            }
            if(date.getMonth()==now.getMonth())
            {
                if(date.getDate()<now.getDate())
                {
                    return true;
                }
            }
        },
        });
    </script>
  4. To reuse the template on several places, just modify the input field like this:

    <input type="text" style="width: 120px;" class="input-text" value="" id="selected_date" name="<?php echo $this->getInputName() ?>"/>

    and in XML, call the block like this:

    <block type="inchoo/calendar" name="frontend_calendar">
                        <action method="setInputName"><input_name>dob</input_name></action>
                    </block>
  5. Hi Branko,
    Thanks for this great post.
    I want to use two calendars for start date and end date.
    I have got that working with two separate script tags with different identifiers but is there a better way to perform this?
    Any help is much appreciated
    Thanks

  6. Is there any way to show up the Embedded Calender, rather than on click event.

    I am using the same logic up there, magento default calendar.

    Thanks

  7. I fixed the issue by adding the calendar block as:

    <checkout_onepage_index>
    	<block type="inchoo/calendar" name="inchoo.calendar" />
    </checkout_onepage_index>

    Also i have one question: I don’t really find the usage of template=calendar.phtml, How to call it from required .phtml?

    Thanks

  8. Hi Branko

    I liked the approach. But when i tried to use the block class i got the following error:
    Fatal error: Call to a member function append() on a non-object in ..
    Note that i am using this code in checkout_onepage_shippingmethod handle.

    Thanks
    Regards

Leave a Reply

Your email address will not be published. Required fields are marked *

You may use these HTML tags and attributes: <a href="" title=""> <blockquote cite=""> <code> <del datetime=""> <em> <s> <strike> <strong>. You may use following syntax for source code: <pre><code>$current = "Inchoo";</code></pre>.