有没有一种方法可以通过单击按钮来捕获带有焦点的onchange触发器?

时间:2019-12-11 16:21:33

标签: javascript jquery ajax odoo

方案是此模式窗口:

enter image description here

带有.on('change', function () {});的输入2、3和4对指定的控制器进行AJAX调用,该控制器将更新Recod值并重新加载值1。 因此,正确但不实用的方法是:

  1. 单击输入1并设置值
  2. 在输入之外单击以对其进行聚焦
  3. AJAX重新加载值1已更新
  4. 单击输入2并设置值
  5. 通过在输入之外单击来突出显示重点
  6. AJAX重新加载值1已更新
  7. 用户单击确认,然后调用另一个控制器进行检查并更改对象的状态(从“草稿”到“已确认”)

问题

如果我这样尝试:

  1. 单击输入1并设置值
  2. 在输入之外单击以对其进行聚焦
  3. AJAX重新加载值1已更新
  4. 单击输入2并设置值
  5. 单击确认按钮,该按钮调用另一个控制器并触发输入更改

现在,以这种方式出现问题是因为确认方法尚未收到上一次onchange触发器的更新,并且检查不正确。

是否可以通过onchangeonclick等不同的触发器来管理多个AJAX?

类似于触发以下onclick之类的东西:

// Trigger for button confirm inside timesheet sheet modal
$(document).on('click', 'button.js_confirm_timesheet_sheet', function (ev) {
    var $button = $(this);
    var wizard_id = $button.data()['wizardId'];
    var sheet_id = $button.data()['sheetId'];
    var values = {
        'wizard_id': wizard_id,
        'sheet_id': sheet_id,
    };
    confirm_sheet_distribution_hours(values);
});

检查点击是否来自输入焦点,如果是,则首先触发onchange,然后触发onclick

也许此解决方案可能是这样做的一种不好方法。

很少,触发摘要:

  • 输入具有onchange触发器,该触发器使用AJAX调用将数据写入后端对象,该AJAX调用重新计算值并返回新值。
  • “确认”按钮通过AJAX调用检查是否一切正常,并更改后端对象状态

另一种解决方法可能是声明一个对象,该对象跟踪每个更改的输入框,并在每次AJAX成功返回时将其清除。

类似的东西:

var changedData = {};

function update_wizard_data_and_modal(values, $input_elem, event) {
    changedData[key] = $input_elem;
    ajax.jsonRpc("/my/controller/path", "call", values)
        .then(function (new_modal_values) {
            $input_elem.removeClass('input-value-error');
            if (!jQuery.isEmptyObject(new_modal_values)) {
                if (new_modal_values.error_msg) {
                    var $content = $(new_modal_values.error_msg);
                    $content.modal({
                        backdrop: 'static',
                        keyboard: false
                    });
                    $content.appendTo('body').modal();
                    // Show error class
                    $input_elem.val('00:00');
                    $input_elem.addClass('input-value-error');
                }
                // Update the header values with hours to be distribuited
                $('#header-wizard-values').html(new_modal_values.header_values);
                // Update the hours to get payed available
                $('.js_hours_to_get_payed').html(new_modal_values.hours_get_payed_values);
                // Clear the changedData object
                for (var member in changedData) delete changedData[member];
            }
        });
}

function confirm_sheet_distribution_hours(values) {
    if jQuery.isEmptyObject(changedData){
        ajax.jsonRpc("/confirm/controller/path", "call", values)
            .then(function (response) {
                if ('error' in response) {
                    //response in this case is the modal error template
                    $(response.error).appendTo('body').modal();
                } else {
                    // Close modal and refresh the grid for current period
                    $('#modal_timesheet_sheet_confirm').modal('hide');
                    var sheet_item_data = {
                        'year': response.year,
                        'month': response.month,
                    };
                    update_grid_and_bars_values(sheet_item_data);
                }

            });
    } else {
       // TODO: trigger the change for element inside object and confirm
    }
}


$(document).on("change", "input.distribution-input", function (ev) {
    var $input = $(this);
    var sheet_id = $('input[name="sheet_id"]').val();
    var wiz_line_id = Number($input.attr('id').match(/\d+/)[0]);
    var row_wizard_data = $input.closest('div.row').data();
    var leave_type_id = row_wizard_data['leaveTypeId'];
    var wizard_id = row_wizard_data['wizardId'];
    var values = {
        'sheet_id': Number(sheet_id),
        'wizard_id': wizard_id,
        'wiz_line_id': wiz_line_id,
        'leave_type_id': leave_type_id,
        'input_value': $input.val(),
    };
    var is_good_formatted = check_string_time_format($input, {});
    if (is_good_formatted) {
        update_wizard_data_and_modal(values, $input, ev);
    }
});

// Trigger for button confirm inside timesheet sheet modal
$(document).on('click', 'button.js_confirm_timesheet_sheet', function (ev) {
    ev.preventDefault();
    ev.stopPropagation();
    var $button = $(this);
    var wizard_id = $button.data()['wizardId'];
    var sheet_id = $button.data()['sheetId'];
    var values = {
        'wizard_id': wizard_id,
        'sheet_id': sheet_id,
    };
    confirm_sheet_distribution_hours(values);
});

1 个答案:

答案 0 :(得分:0)

根据塔普拉(Taplar)的建议,我使用了类似的方法。

这是在Odoo前端中管理向导的“ onchange”的javascript。

// Variable used for the last input changed when user click the Confirm button
var canConfirm = true;
/* Variable used for keep trace of the number of retry inside method
 * confirm_sheet_distribution_hours
 * */
var nr_of_try = 0;

function update_wizard_data_and_modal(values, $input_elem, event) {
    if (event.type !== 'input') {
        ajax.jsonRpc("/controller/path/...", "call", values)
            .then(function (new_modal_values) {
                canConfirm = true;
                $input_elem.removeClass('input-value-error');
                if (!jQuery.isEmptyObject(new_modal_values)) {
                    if (new_modal_values.error_msg) {
                        var $content = $(new_modal_values.error_msg);
                        $content.modal({
                            backdrop: 'static',
                            keyboard: false
                        });
                        $content.appendTo('body').modal();
                        // Show error class
                        $input_elem.val('00:00');
                        $input_elem.addClass('input-value-error');
                    }
                    // Update the header values with hours to be distribuited
                    $('#header-wizard-values').html(new_modal_values.header_values);
                    // Update the hours to get payed available
                    $('.js_hours_to_get_payed').html(new_modal_values.hours_get_payed_values);
                }
            });
    } else {
        canConfirm = false;
    }
}

function set_the_amount_on_wizard($input, values, event) {
    if (event.type !== 'input') {
        ajax.jsonRpc("/controller/path/...", "call", values)
            .then(function (response) {
                canConfirm = true;
                if ('error' in response) {
                    //response in this case is the modal error template
                    $(response.error).appendTo('body').modal();
                    // Reset input value (backend reset the TransientModel value)
                    $input.val('00:00')
                }
            });
    } else {
        canConfirm = false;
    }
}

function confirm_sheet_distribution_hours(values) {
    if (canConfirm) {
        ajax.jsonRpc("/controller/patH/...", "call", values)
            .then(function (response) {
                if ('error' in response) {
                    //response in this case is the modal error template
                    $(response.error).appendTo('body').modal();
                } else {
                    // Close modal and refresh the grid for current period
                    $('#modal_timesheet_sheet_confirm').modal('hide');
                    var sheet_item_data = {
                        'year': response.year,
                        'month': response.month,
                    };
                    update_grid_and_bars_values(sheet_item_data);
                }

            });
    } else {
        /*Try six times to confirm the sheet (Until the onchange doesn't write 
         * new values the AJAX call doesn't set canConfirm as True
         * */
        if (nr_of_try <= 5) {
            setTimeout(function () {
                nr_of_try++;
                confirm_sheet_distribution_hours(values);
            }, 500);
        }
    }
}

//Trigger that monitorate hours distribution change
$(document).on("input change", "input.distribution-input", function (ev) {
    var $input = $(this);
    var sheet_id = $('input[name="sheet_id"]').val();
    var wiz_line_id = Number($input.attr('id').match(/\d+/)[0]);
    var row_wizard_data = $input.closest('div.row').data();
    var leave_type_id = row_wizard_data['leaveTypeId'];
    var wizard_id = row_wizard_data['wizardId'];
    var values = {
        'sheet_id': Number(sheet_id),
        'wizard_id': wizard_id,
        'wiz_line_id': wiz_line_id,
        'leave_type_id': leave_type_id,
        'input_value': $input.val(),
    };
    var is_good_formatted = check_string_time_format($input);
    if (is_good_formatted) {
        update_wizard_data_and_modal(values, $input, ev);
    }
});

//Trigger that monitorate hours distribution change
$(document).on("input change", "input.payment-hour-input", function (ev) {
    var $input = $(this);
    var row_wizard_data = $input.closest('div.row').data();
    var wizard_id = row_wizard_data['wizardId'];
    var values = {
        'wizard_id': wizard_id,
        'input_value': $input.val(),
    };
    var is_good_formatted = check_string_time_format($input);
    if (is_good_formatted) {
        set_the_amount_on_wizard($input, values, ev);
    }
});

// Trigger for button confirm inside timesheet sheet modal
$(document).on('click', 'button.js_confirm_timesheet_sheet', function (ev) {
    var $button = $(this);
    var wizard_id = $button.data()['wizardId'];
    var sheet_id = $button.data()['sheetId'];
    var values = {
        'wizard_id': wizard_id,
        'sheet_id': sheet_id,
    };
    // Variable used for retry sheet confirmation until canConfirm is not True
    // Max repeat call is 6 times
    nr_of_try = 0;
    confirm_sheet_distribution_hours(values);
});

简单来说。 当用户在输入框上键入内容时,input内的on.()类型会将变量canConfirm设置为false。 这样可以防止用户更改值并在之后立即单击“确认”按钮的情况。

实际上,如果用户更改某些输入框并立即单击“确认”,则仅当标志为true时AAAX调用才会开始,否则,该方法每500毫秒调用一次其自身。

让我知道是否有更好的方法可以做到这一点。 谢谢

PS:我将使用DTO后端尝试一种更好的方法,该方法可从模型中克隆数据并管理onchange缓存之类的更新。

灵感来自:https://python-3-patterns-idioms-test.readthedocs.io/en/latest/Messenger.html