🤔چطور می‌توانم یک آیتم از نوع Number Filed را تبدیل به Numeric Spinner کنم؟


نیازمندی‌ها

  1. دو دکمه در جلوی آیتم که روی هم قراربگیرند و برای کم و زیاد کردن مقدار استفاده شوند.

  2. برای دکمه‌ها +/- مقدار پیش‌فرض مقدار یک باشد و توسط کاربر قابل تنظیم باشد.

  3. اگر آیتم دارای focus بود، با حرکت غلتک (scroll) ماوس، مقدار کم و زیاد شود.

  4. برای غلتک، مقدار پیش‌فرض 10 باشد و توسط کاربر هم قابل تنظیم باشد.

  5. امکان منفی شدن مقدار، توسط کاربر مشخص شود. در حالت پیش‌فرض مقدار منفی مجاز نیست.

  6. اعداد ممکن است دارای جدا کننده (Grouping Separator) باشند.

🔔 به صورت پیش‌فرض برای این نوع آیتم type = text هست که می‌شود آن را به number تغییر داد تا دکمه‌های inc/dec نمایان شوند. اما من از این روش استفاده نمی‌کنم.


پیاده‌سازی

  1. بر روی آیتم مورد نظر (مثلا P7_ORDER_NO) کلیک کرده و برای Post Text آن، مقداری به دلخواه می‌نویسیم. من از * استفاده کردم. بدین ترتیب span این قسمت با کلاس «t-Form-itemText–post» فعال می‌شود. با استفاده از jQuery ، دکمه‌ها را در این قسمت قرار می‌دهیم.
Advanced | Post Text: *

Advanced | Post Text: *

  1. برای قرارگرفتن کادر دور دکمه‌ها Display as Block مربوط به آیتم را انتخاب می‌کنیم.
Appearance | Template Options | Item Post Text: Display as Block

Appearance | Template Options | Item Post Text: Display as Block

  1. در قسمت JavaScript صفحه در Execute when Page Loads از متد Item_NumericSpinner استفاده می‌کنیم.

کد JS را می‌توانیم در قسمت Function and Global Variable Declaration بنویسیم. من از فایل در قسمت static fileها استفاده می‌کنم ( لینک GitHub ).

/**
 * ایجاد حالت +/- کردن به فیلد عددی
 * 
 ** type: number field
 ** برای قرارگرفتن دکمه > post text = *
 * 
 * 
 * @param itemName > نام آیتم
 * @param wheel_step >  مقداری که با چرخ موس باید اضافه/کم شود
 * @param ud_step > up-down مقداری که باید اضافه/کم شود
 * @param negative > باشد false جلوگیری از مقدار منفی اگر مقدار
 * @param groupingSymbol > کاراکتر جداکننده ارقام
 */
function Item_NumericSpinner(itemName, wheel_step = 10, ud_step = 1, negative = false, groupingSymbol = ',') {

    let containter$ = $("#" + itemName + "_CONTAINER .t-Form-itemText--post");

    let css_btn = { background: "none", border: "none", cursor: "pointer" };
    let css_div = { display: "inline-flex", "flex-direction": "column", "vertical-align": "middle" };

    let div$ = $('<div>').css(css_div);
    let btnUp$ = $('<button>', { type: "button", text: '▲' }).css(css_btn);
    let btnDown$ = $('<button>', { type: "button", text: '▼' }).css(css_btn);

    div$.append(btnUp$);
    div$.append(btnDown$);
    containter$.html(div$);
    //----------------------------------------------
    let item$ = $("#" + itemName);

    btnUp$.on("click",  inc.bind(null,ud_step));
    btnDown$.on("click", dec.bind(null,ud_step));

    item$.on("wheel", function (e) {
        e.preventDefault();

        // آیا فوکوس دارد؟
        if (document.activeElement.id !== itemName) 
            return;

        let delta = e.originalEvent.deltaY;

        if (delta < 0) {
            inc(wheel_step);
        } else {
            dec(wheel_step);
        }

    });

    function inc(step) {
        let val = parseFloat(item$.val().replace(groupingSymbol, '')) || 0;
        item$.val(val + step);
        // apex.item(itemName).setValue(item$.val());
    }

    function dec(step) {
        let val = parseFloat(item$.val().replace(groupingSymbol, '')) || 0;

        val = val - step
        if (negative == false & val < 0) val = 0;

        item$.val(val);
        // apex.item(itemName).setValue(item$.val());         
    }
}

🧐🧠خلاصه کارهایی که انجام دادم

  • آیا می‌شود در قسمت Post Text از کد HTML استفاده کرد؟ بله
  • از ChatGPT خواستم کد این کار را برایم ایجاد کند … که در نهایت خروجی آن شامل سه قسمت شد: کد دکمه‌ها، CSS و کد JS.
  • چرخه‌ی تست، رفع اشکال، بازبینی، ایده‌ی جدید و …
  • برای اینکه بتوانم از این کد به دفعات استفاده کنم، آن را تبدیل به function کردم.
  • برای اینکه کاربر مجبور به استفاده از کد CSS و کد دکمه‌ها نباشد، آن را در متد JS ادغام کردم.
  • برای حذف تکرار، از nested function استفاده کردم (تابع تو در تو).
  • چون این کد را برای Item استفاده کردم، برای دسته بندی بهتر، آن را در فایلی به نام site_Item.js نگهداری می‌کنم که در این فایل برای نام متدها از پیشوند Item استفاده کردم و خواهم کرد.

💡 تمام فایل‌های JS را در نهایت به فایل site.js تبدیل می‌کنم و در محیط production استفاده می‌کنم.