Fading Coder

One Final Commit for the Last Sprint

Home > Notes > Content

Customizing jQuery EasyUI DateBox for Granular Year-Month Selection and Period-Driven Formatting

Notes May 4 12

The following implementation demonstrates how to restrict the jQuery EasyUI datebox component to year-month granularity while dynamically adjusting its display behavior based on an external period selector. Additionally, a lightweight alternative using combobox is provided for single-year selection scenarios.

HTML Structure

<input id="yymmSelector" class="easyui-datebox" data-options="editable:false">
<select id="periodSelector" class="easyui-combobox" data-options="value:'YM',prompt:'Select Period'">
    <option value="YM">Year-Month</option>
    <option value="Y">Year Only</option>
</select>

Configuration & Event Handling

Initialize the date picker by intercepting the panel expansion event to hijack the day-view rendering process. This forces the UI to display only the month grid while suppressing the calendar tooolbar and day cells.

function initializeDateControl() {
    const $picker = $('#yymmSelector');
    let monthGridElements = null;
    let triggerSpan = null;

    $picker.datebox({
        onShowPanel: function () {
            if (!triggerSpan) {
                triggerSpan = $picker.parent().find('span.calendar-text');
            }
            
            // Force month view by simulating header click
            triggerSpan.trigger('click');

            if (!monthGridElements) {
                setTimeout(() => {
                    const panel = $picker.datebox('panel');
                    monthGridElements = panel.find('div.calendar-menu-month-inner td');
                    
                    monthGridElements.on('click.yymod', function (e) {
                        e.stopPropagation();
                        
                        const currentYear = /\d{4}/.exec(triggerSpan.text())[0];
                        const selectedMonth = parseInt($(this).attr('abbr'), 10) + 1;
                        
                        $picker.datebox('hidePanel');
                        $picker.datebox('setValue', `${currentYear}-${String(selectedMonth).padStart(2, '0')}`);
                    });
                }, 50);
            }
        },
        parser: function (valStr) {
            if (!valStr) return new Date();
            const [yearPart, monthPart] = valStr.split('-');
            return new Date(parseInt(yearPart, 10), parseInt(monthPart, 10) - 1, 1);
        },
        formatter: function (dateObj) {
            const periodMode = $('#periodSelector').combobox('getValue');
            
            if (periodMode === 'Y') {
                return String(dateObj.getFullYear());
            }
            
            const mm = String(dateObj.getMonth() + 1).padStart(2, '0');
            return `${dateObj.getFullYear()}-${mm}`;
        }
    });

    // Set default value to current month
    const now = new Date();
    const defaultVal = formatDateForPicker(now);
    $picker.datebox('setValue', defaultVal);
}

function formatDateForPicker(targetDate) {
    const mode = $('#periodSelector').combobox('getValue');
    if (mode === 'Y') return String(targetDate.getFullYear());
    
    const m = targetDate.getMonth() + 1;
    return `${targetDate.getFullYear()}-${String(m).padStart(2, '0')}`;
}

Dynamic Value Synchronization

Link the exetrnal period dropdown to the date control so that switching modes automatically recalcualtes and formats the displayed value according to the selected granularity.

function syncValueBasedOnPeriod() {
    const mode = $('#periodSelector').combobox('getValue');
    const existingVal = $('#yymmSelector').datebox('getValue');
    const today = new Date();
    
    let calculatedValue = '';
    
    if (mode === 'Y') {
        calculatedValue = String(today.getFullYear());
        if (existingVal.includes('-')) {
            $('#yymmSelector').datebox('setValue', calculatedValue);
        }
    } else {
        const nextMonth = today.getMonth() === 11 ? 0 : today.getMonth();
        const adjYear = today.getMonth() === 11 ? today.getFullYear() - 1 : today.getFullYear();
        calculatedValue = `${adjYear}-${String(nextMonth + 1).padStart(2, '0')}`;
        
        if (!existingVal.includes('-')) {
            $('#yymmSelector').datebox('setValue', calculatedValue);
        }
    }
}

// Attach listener
$('#periodSelector').on('change.combobox', syncValueBasedOnPeriod);

Alternative: Standalone Year-Only Selector

When only year selection is required, replacing the datebox with a combobox reduces DOM overhead and simplifies state management.

function setupYearDropdown() {
    const startYear = 2018;
    const endYear = 2030;
    const options = Array.from({ length: endYear - startYear + 1 }, (_, i) => {
        const y = startYear + i;
        return { timeName: String(y), timeCode: String(y) };
    });

    $('#yymmSelector').combobox({
        data: options,
        editable: false,
        valueField: 'timeCode',
        textField: 'timeName',
        onSelect: function (rec) {
            console.log('Selected Year:', rec.timeName);
        }
    });

    const currentYear = new Date().getMonth() > 0 ? new Date().getFullYear() : new Date().getFullYear() - 1;
    $('#yymmSelector').combobox('setValue', String(currentYear));
}

Related Articles

Designing Alertmanager Templates for Prometheus Notifications

How to craft Alertmanager templates to format alert messages, improving clarity and presentation. Alertmanager uses Go’s text/template engine with additional helper functions. Alerting rules referenc...

Deploying a Maven Web Application to Tomcat 9 Using the Tomcat Manager

Tomcat 9 does not provide a dedicated Maven plugin. The Tomcat Manager interface, however, is backward-compatible, so the Tomcat 7 Maven Plugin can be used to deploy to Tomcat 9. This guide shows two...

Spring Boot MyBatis with Two MySQL DataSources Using Druid

Required dependencies application.properties: define two data sources and poooling Java configuration for both data sources MyBatis mappers for each data source Controller endpoints to verify both co...

Leave a Comment

Anonymous

◎Feel free to join the discussion and share your thoughts.