javascript - 为什么当发送 AJAX req.js 的函数时,JS 生成的表单会在表单生成后立即触发 AJAX 请求。绑定(bind)到onsubmit事件?

标签 javascript php forms validation dom

我正在编写一个带有注册登录注销功能的简单网络应用程序作为练习任务。后端逻辑采用 PHP,客户端部分采用纯 HTML/CSS/Javascript。我被要求根据当前范围(注册或登录)动态生成注册/登录表单,因此我决定使用 Javascript 生成表单并发送表单数据(并接收验证错误消息)使用 AJAX 请求(JSON 格式)发送到服务器。

问题是生成表单时,自动触发 AJAX 请求,而无需单击“登录/注册”按钮。而且,发送 AJAX 请求的函数似乎无法获取输入来自输入字段的值,因此它仅发送范围。

每次重新生成表单时(因为范围已更改),它都会重新发送 AJAX 请求。

我已经尝试在单击“登录/注册”按钮时调用该函数,并仅在生成函数时将函数绑定(bind)到表单,但没有任何帮助。

以下是发送 AJAX 的函数:

function sendAjax(data) {
    let xhr = new XMLHttpRequest();
    xhr.open("POST", "process.php");
    xhr.setRequestHeader("Content-Type", "application/json");
    xhr.onreadystatechange = function() {
        if (xhr.readyState === 4 && xhr.status === 200) {
            let resData = JSON.parse(this.responseText);
            Object.keys(resData).forEach(function (key) {
                let e = resData[key];
                if(document.getElementById(key+"span")!==null){
                    let div = document.getElementById(key+"G");
                    div.classList.add("has-error");
                    let span = document.getElementById(key+"span");
                    span.innerHTML = e;
                }
            });
        }
    };
    xhr.send(data);
}

function process(scope) {
    let inputs = document.getElementsByTagName("input");
    console.log(inputs);
    let filteredInputs = [];
    for(let i = 0; i < inputs.length; i++){
        if(inputs[i].type !== "submit"){
            filteredInputs.push(inputs[i]);
        }
    }
    console.log(filteredInputs);
    let data = {scope: scope};
    for(let i = 0; i < inputs.length; i++){
        data[filteredInputs[i].name] = filteredInputs[i].value;
    }
    let dataJSON = JSON.stringify(data);
    sendAjax(dataJSON);
    return false;
}

这就是表单的生成方式:


let session = {
    scope: "login",
    setScope: function (scope) {
        this.scope = scope;
        document.getElementById("form-wrapper").appendChild(createForm(scope));
    }
};

function createForm(scope){
    if(document.getElementById("form")!==null){
        let form = document.getElementById("form");
        document.getElementById("form-wrapper").removeChild(form);
    }
    let form = document.createElement("form");
    form.id = "form";
    let buttons = document.createElement("div");
    buttons.className = "form-group";
    let title = document.createElement("h2");
    if(scope === "login"){
        title.innerHTML = "Bejelentkezés";
        form.appendChild(title);
        form.appendChild(createFormGroup("email"));
        form.appendChild(createFormGroup("password"));
        let login = document.createElement("input");
        login.type = "submit";
        login.className = "btn btn-primary";
        login.value = "Bejelentkezés";
        login.id = "btn-submit";
        buttons.appendChild(login);
    }
    if(scope === "register"){
        title.innerHTML = "Regisztráció";
        form.appendChild(title);
        formElementProps.forEach(((value, key) => form.appendChild(createFormGroup(key))));
        let register = document.createElement("input");
        register.type = "submit";
        register.className = "btn btn-primary";
        register.value = "Regisztráció";
        register.id = "btn-submit";
        let reset = document.createElement("input");
        reset.type = "reset";
        reset.className = "btn btn-deafult";
        reset.value = "Törlés";
        buttons.appendChild(register);
        buttons.appendChild(reset);
    }
    let link = createLink(scope);
    form.appendChild(buttons);
    form.appendChild(link);
    form.onsubmit = process(scope);
    return form;
}

document.addEventListener('DOMContentLoaded', function () {
    document.getElementById("form-wrapper").appendChild(createForm(session.scope));
});

后端逻辑看起来很好,因为当它自动触发时,它会响应正确的错误消息。

最佳答案

您的问题出在这一行:

form.onsubmit = process(scope);

这会将函数调用 process(scope)结果作为 formonsubmit 属性传递。这当然没有任何意义,因为结果(返回值)是false。但这确实意味着该函数被调用,从而在调用 createForm 函数时触发您的 Ajax。这正是您所提示的行为。

要解决这个问题,您可以记忆一下 form.onsubmit 像所有 HTML 属性一样,应该是一个“字符串”,在本例中是一个 JS 代码字符串,当提交事件时将对其进行评估发生。因此,这个看似微不足道的更改应该按预期工作(编辑:实际上不会,请参阅下面的评论):

form.onsubmit = "process(scope)";

但是,使用 HTML on*** 属性来传递被评估为 JS 代码的字符串并不是很好的做法。更好的是使用 addEventListener 方法,并将应调用的实际函数传递给它。这里应该是:

form.addEventListener("submit", function() {
    process(scope);
});

请注意,传递给 addEventListener 的第二个参数是一个函数 - 您可能会想要这样做

form.addEventListener("submit", process(scope));

但这会与您最初遇到的问题发生冲突 - process(scope) 将在遇到该行后立即执行,并且其返回值预计是一个函数(当然不是)。

关于javascript - 为什么当发送 AJAX req.js 的函数时,JS 生成的表单会在表单生成后立即触发 AJAX 请求。绑定(bind)到onsubmit事件?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/57209731/

相关文章:

javascript - 如何创建jQuery元素缓存机制?

javascript - jQuery 删除 var 上的两个元素

javascript - 如何使用 JavaScript 检测页面加载时(即不是按键时)的大写锁定状态?

c# - 我如何遍历特定表单的所有打开实例?

javascript - 确认消息未显示在 JavaScript 联系表单上

javascript - 使用 Angular js根据下拉列表中选定的输入隐藏表单中的字段

javascript - 如何映射对象数组的名称以更改字段名称?

php - 无法使用php连接到本地数据库

php - MySQL 中如何匹配 id

javascript - jQuery : Want to disable all the input fields if editqastatus value = 1 or 2