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 1

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...

Skipping Errors in MySQL Asynchronous Replication

When a replica halts because the SQL thread encounters an error, you can resume replication by skipping the problematic event(s). Two common approaches are available. Methods to Skip Errors 1) Skip a...

Leave a Comment

Anonymous

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