You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

在Sage Intacct中使用jQuery事件监听器时自动生成字段被清除的问题求助

Issue: Auto-populated fields cleared when selecting item combobox after project in multi-row Sage Intacct table (jQuery)

Problem Description

I'm working on a Sage Intacct customization using jQuery to implement real-time table updates: when users enter quantity and price, the system calculates and updates the total amount field automatically. This works perfectly for single rows, but I'm hitting a bug with multi-row scenarios:

  1. When adding a new row
  2. First selecting a project pulled from an API
  3. Then selecting an item from the corresponding combobox

The auto-populated fields (like state, opportunity type, vertical) get cleared, while manually entered fields (quantity/price) remain intact. Strangely, this only happens when the task field is updated via the item selection logic, even though the task update code follows the same pattern as other auto-population logic.

Code Snippets

Quantity/Price/Total Change Listeners

jq('#' + qtyid).on('change', function() { 
    var qty = jq('#' + qtyid)[0].value; 
    var rate = jq('#' + rateid)[0].value; 
    var oriamt = jq('#' + amtid)[0].value; 
    var totamnt = jq('#' + totalid)[0].value; 
    var newamt = 0; 
    if(qty == '') qty = 0; 
    if(rate == '') rate = 0; 
    try{ qty = parseFloat(qty.replace(',','')); }catch(e){ qty = parseFloat(qty); } 
    try{ rate = parseFloat(rate.replace(',','')); }catch(e){ rate = parseFloat(rate); } 
    newamt = qty * rate; 
    jq(row).find('#' + amtid).val(newamt.toFixed(2)); 
    jq(row).find('#' + totalid).val(qty); 
    window.editor.data.view.ENTRIES[0].AMOUNT_CONVERTED = qty; 
    window.editor.data.view.ENTRIES[0].TOTAL_AMOUNT = newamt; 
    window.editor.data.view.ENTRIES[0].UIPRICE = rate; 
});

jq('#' + rateid).on('change', function() { 
    console.log('rate changed'); 
    var qty = jq('#' + qtyid)[0].value; 
    var rate = jq('#' + rateid)[0].value; 
    var oriamt = jq('#' + amtid)[0].value; 
    var totamnt = jq('#' + totalid)[0].value; 
    var newamt = 0; 
    if(qty == '') qty = 0; 
    if(rate == '') rate = 0; 
    qty = parseFloat(qty.replace(',','')); 
    rate = parseFloat(rate.replace(',','')); 
    newamt = qty * rate; 
    jq(row).find('#' + amtid).val(newamt.toFixed(2)); 
    jq(row).find('#' + price).val(rate); 
    jq(row).find('#' + grandtotal).val(totamnt * rate); 
});

jq('#' + totalid).on('input', function() { 
    var qty = jq('#' + qtyid)[0].value; 
    var rate = jq('#' + rateid)[0].value; 
    var oriamt = jq('#' + amtid)[0].value; 
    var totamnt = jq('#' + totalid)[0].value; 
    jq(row).find('#' + grandtotal).val(totamnt * rate); 
});

Project/Item/Task Change Listeners

jq(row).find('#' + projectid).on('change', function() { 
    var project = ""; 
    var temp = jq(row).find('#' + projectid).val(); 
    if (temp.includes("--")) { 
        project = temp.split("--")[0]; 
    } else { 
        project = temp; 
    } 
    var selproject = _projectlist.find(x => x.PROJECTID == project); 
    var state = _statelist.find(x => x.id == selproject.RSTATE); 
    var optype = _optypelist.find(x => x.id == selproject.ROPPORTUNITY_TYPE_TEST); 
    var opvertical = _opverticallist.find(x => x.id == selproject.ROPPORTUNITY_VERTICAL_TEST); 
    jq(row).find('#' + stateid).val(state.name); 
    window.editor.data.view.ENTRIES[rowind].GLDIMSTATE_disp = state.name; 
    window.editor.data.view.ENTRIES[rowind].GLDIMSTATE = state.id; 
    jq(row).find('#' + optypeid).val(optype.name); 
    window.editor.data.view.ENTRIES[rowind].GLDIMOPPORTUNITY_TYPE_TEST_disp = optype.name; 
    window.editor.data.view.ENTRIES[rowind].GLDIMOPPORTUNITY_TYPE_TEST = optype.id; 
    jq(row).find('#' + opverticalid).val(opvertical.name); 
    window.editor.data.view.ENTRIES[rowind].GLDIMOPPORTUNITY_VERTICAL_TEST_disp = opvertical.name; 
    window.editor.data.view.ENTRIES[rowind].GLDIMOPPORTUNITY_VERTICAL_TEST = opvertical.id; 
});

jq(row).find('#' + itemid).on('change', function() { 
    var item = ""; 
    var temp = jq(row).find('#' + itemid).val(); 
    if (temp.includes("--")) { 
        item = temp.split("--")[0]; 
    } else { 
        item = temp; 
    } 
    var selitem = _itemlist.find(x => x.ITEMID == item); 
    if (selitem != undefined) { 
        var task = selitem.TASK_MAPPING; 
        jq(row).find('#' + taskid).val(task); 
        window.editor.data.view.ENTRIES[rowind].TASKID = task; 
    } 
});

Field ID Generation Logic

jq('#tbody__obj__ENTRIES').each(function(i, tb){ 
    jq('#tbody__obj__ENTRIES > tr').each(function(rowind, row) { 
        var qtyid = '_obj__ENTRIES_' + rowind + '_-_obj__AMOUNT_CONVERTED'; 
        var rateid = '_obj__ENTRIES_' + rowind + '_-_obj__KERRPRICE'; 
        var amtid = '_obj__ENTRIES_' + rowind + '_-_obj__TOTAL_AMOUNT'; 
        var totalid = '_obj__ENTRIES_' + rowind + '_-_obj__TOTAL_CONVERTED'; 
        var price = '_obj__ENTRIES_' + rowind + '_-_obj__UIPRICE'; 
        var extprice = '_obj__ENTRIES_' + rowind + '_-_obj__UIVALUE'; 
        var grandtotal = '_obj__ENTRIES_' + rowind + '_-_obj__GRAND_TOTAL'; 
        var projectid = '_obj__ENTRIES_' + rowind + '_-_obj__PROJECTID'; 
        var itemid = '_obj__ENTRIES_' + rowind + '_-_obj__ITEMID'; 
        var stateid = '_obj__ENTRIES_' + rowind + '_-_obj__GLDIMSTATE'; 
        var opverticalid = '_obj__ENTRIES_' + rowind + '_-_obj__GLDIMOPPORTUNITY_VERTICAL_TEST'; 
        var optypeid = '_obj__ENTRIES_' + rowind + '_-_obj__GLDIMOPPORTUNITY_TYPE_TEST'; 
        var taskid = '_obj__ENTRIES_' + rowind + '_-_obj__TASKID';
        // Event bindings here
    });
});

Troubleshooting Context

  • I didn't write the original code, I'm tasked with fixing this bug
  • The code logic is messy, and I can't pinpoint exactly why only auto-populated fields get cleared on item selection
  • Manual input fields remain intact, suggesting the issue is related to how auto-populated data is stored/updated

Solutions to Fix the Issue

1. Fix Closure Scope for Row Index (Most Likely Root Cause)

The original loop binds events using the rowind variable directly, which creates a closure issue: all events end up referencing the last row's index instead of the current row's. Use an IIFE (Immediately Invoked Function Expression) to capture the current row and index:

jq('#tbody__obj__ENTRIES > tr').each(function(rowind, row) {
    // Capture current row and index in a closure
    (function(currentRowInd, currentRow) {
        // Generate IDs as before
        var qtyid = '_obj__ENTRIES_' + currentRowInd + '_-_obj__AMOUNT_CONVERTED';
        var rateid = '_obj__ENTRIES_' + currentRowInd + '_-_obj__KERRPRICE';
        // ... rest of ID generation

        // Rewrite all event bindings to use currentRowInd and currentRow
        jq(currentRow).find('#' + projectid).on('change', function() {
            var project = "";
            var temp = jq(this).val();
            if (temp.includes("--")) {
                project = temp.split("--")[0];
            } else {
                project = temp;
            }
            var selproject = _projectlist.find(x => x.PROJECTID == project);
            if (!selproject) return;
            
            var state = _statelist.find(x => x.id == selproject.RSTATE);
            var optype = _optypelist.find(x => x.id == selproject.ROPPORTUNITY_TYPE_TEST);
            var opvertical = _opverticallist.find(x => x.id == selproject.ROPPORTUNITY_VERTICAL_TEST);
            
            jq(currentRow).find('#' + stateid).val(state.name);
            window.editor.data.view.ENTRIES[currentRowInd].GLDIMSTATE_disp = state.name;
            window.editor.data.view.ENTRIES[currentRowInd].GLDIMSTATE = state.id;
            
            // ... rest of project auto-population logic
        });

        // Rewrite item/task binding similarly
        jq(currentRow).find('#' + itemid).on('change', function() {
            var item = "";
            var temp = jq(this).val();
            if (temp.includes("--")) {
                item = temp.split("--")[0];
            } else {
                item = temp;
            }
            var selitem = _itemlist.find(x => x.ITEMID == item);
            if (selitem != undefined) {
                var task = selitem.TASK_MAPPING;
                jq(currentRow).find('#' + taskid).val(task);
                window.editor.data.view.ENTRIES[currentRowInd].TASKID = task;
            }
        });

        // Rewrite quantity/price/total bindings using currentRowInd and currentRow
    })(rowind, row);
});

2. Use Event Delegation for Dynamic Rows

Since rows are added dynamically, event bindings on initial rows won't apply to new rows. Bind events to the parent <tbody> element instead:

// Delegate project change event
jq('#tbody__obj__ENTRIES').on('change', '[id^="_obj__ENTRIES_"][id$="_-_obj__PROJECTID"]', function() {
    var currentRow = jq(this).closest('tr');
    var rowind = currentRow.index();
    
    // Parse IDs or generate them based on rowind
    var stateid = '_obj__ENTRIES_' + rowind + '_-_obj__GLDIMSTATE';
    var optypeid = '_obj__ENTRIES_' + rowind + '_-_obj__GLDIMOPPORTUNITY_TYPE_TEST';
    // ... rest of ID generation
    
    // Project auto-population logic here, using currentRow and rowind
});

// Delegate item change event
jq('#tbody__obj__ENTRIES').on('change', '[id^="_obj__ENTRIES_"][id$="_-_obj__ITEMID"]', function() {
    var currentRow = jq(this).closest('tr');
    var rowind = currentRow.index();
    
    var temp = jq(this).val();
    var item = temp.includes("--") ? temp.split("--")[0] : temp;
    var selitem = _itemlist.find(x => x.ITEMID == item);
    if (selitem != undefined) {
        var task = selitem.TASK_MAPPING;
        var taskid = '_obj__ENTRIES_' + rowind + '_-_obj__TASKID';
        jq(currentRow).find('#' + taskid).val(task);
        window.editor.data.view.ENTRIES[rowind].TASKID = task;
    }

    // Optional: Re-trigger project change to restore cleared fields
    var projectid = '_obj__ENTRIES_' + rowind + '_-_obj__PROJECTID';
    jq(currentRow).find('#' + projectid).trigger('change');
});

3. Prevent Sage Intacct Native Field Reset

Sage Intacct may trigger native form events when selecting items that reset auto-populated fields. Add event prevention and re-trigger project auto-population:

jq(currentRow).find('#' + itemid).on('change', function(e) {
    e.preventDefault();
    e.stopPropagation();
    
    // Original item/task logic here
    
    // Re-run project auto-population to restore cleared fields
    jq(currentRow).find('#' + projectid).trigger('change');
});

Key Takeaways

The most probable issues are closure-related index errors or missing event bindings for dynamic rows. Start with fixing the closure scope and implementing event delegation, as these address the core problems with multi-row interactions in Sage Intacct.

内容的提问来源于stack exchange,提问作者mferraro

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.04.27 18:38:09