重置表单无效值

6
这是一个样例表单:

var form = document.querySelector('form');

function detectChange() {
  var inputs = form.querySelectorAll('input');
  for (var input of inputs) {
    if (input.value != input.defaultValue) {
      return true;
    }
  }
}

form.querySelector('button').addEventListener('click', function() {
  if (detectChange() && confirm('Are you sure you want to reset?')) {
    form.reset();
  }
});
<form>
  <input type="number">
  <input type="number" value="7">
  <button type="button">Reset</button>
</form>

我希望重置按钮即使用户输入非数字值也能起作用。

@SyedMehtabHassan:你甚至可以在Chrome中完成它:将一些文本复制并粘贴到输入字段中。 - Mori
循环遍历表单元素并将值设置为“ ”。 - Syed Mehtab Hassan
@SyedMehtabHassan 输入"e1231e222",虽然它是无效的,但它允许你输入。 - Mark Schultheiss
可能是 https://dev59.com/cGMk5IYBdhLWcg3w6yHh#18853513 的重复问题。 - connexo
@connexo:然后确认出现,当您点击“确定”时,输入框将恢复其默认值,即10。请在我的演示中尝试。 - Mori
显示剩余6条评论
8个回答

9
如果你查看`input` DOM对象,你会发现在`validity`对象下有一个名为`badInput`的属性,它的值是一个布尔类型。对于数值输入或者空字段,它的值为`false`。然而,对于非数值类型的输入,它的值为`true`,这可以在你的情况下很有趣地使用。
注意:该方法仅在`firefox`和`safari`中测试过。
input
|  +-- ...
|  +-- validity
|  |   +-- badInput
|  |   +-- ...
|  +-- ...

利用这些知识,您可以修改函数以检查badInput,并且只需进行最少的调整即可实现您想要的效果。

// non-empty and non default
if ((input.value && input.value != input.defaultValue) || input.validity.badInput)

var form = document.querySelector('form');

function detectChange() {
  var inputs = form.querySelectorAll('input');
  for (var input of inputs) {
    if ((input.value && input.value != input.defaultValue) || input.validity.badInput) {
      return true;
    }
  }
}

form.querySelector('button').addEventListener('click', function() {
  if (detectChange() && confirm('Are you sure you want to reset?')) {
    form.reset();
  }
});
<form>
  <input type="number">
  <input type="number" value="11">
  <button type="button">Reset</button>
</form>

更新:

更新以包含:

带有非空默认值的输入


在Firefox上似乎运行良好,您能详细说明一下吗? - 1565986223
1
我错了,input.value将返回字符串"0"而不是数字0,后者会被视为false - connexo
是的,我认为这有点奇怪,因为输入类型为“number” - 1565986223
1
任何类型的 input 都只会保存 string 值。 - connexo
1
HTMLFormElement.reset() 方法可以恢复表单元素的默认值。默认值并不总是空字符串。如果要将代码段推广到具有非空默认值的输入,请使用以下代码:if (input.value != input.defaultValue || input.validity.badInput)演示 - Mori
我更新了我的问题以防止混淆。 - Mori

2
实现您的目标的一种替代方案是使用一组标准的伪类,例如:invalid:valid。此外,请注意,我们将使用一些数组方法和特性,例如Array.some()Spread Syntax

var form = document.querySelector('form');

function detectChange()
{
    var invalids = form.querySelectorAll('input:invalid');
    var valids = form.querySelectorAll('input:valid');
    return (invalids.length > 0) || [...valids].some(i => i.defaultValue !== i.value);
}

form.querySelector('button').addEventListener('click', function()
{
    if (detectChange() && confirm('Are you sure you want to reset?'))
        form.reset();
});
<form>
  <input type="number">
  <input type="number">
  <input type="number" value="7">
  <button type="button">Reset</button>
</form>

如果您能在输入框中使用占位符,则另一个可能的解决方案是使用CSS伪类:placeholder-shown。但是,请检查浏览器支持,以确保它适合您的需要。请注意,它是实验性的,不建议在生产环境中使用。然后,您可以使用下一个选择器
input:not(:placeholder-shown)

获取所有未显示占位符的输入,即所有非空输入,并重新实现您的代码,类似于以下方式:

var form = document.querySelector('form');

function detectChange()
{
    var inputs = form.querySelectorAll(
        'input:not([value]):not(:placeholder-shown), input[value]'
    );
    return [...inputs].some(i => !i.defaultValue || i.defaultValue !== i.value);
}

form.querySelector('button').addEventListener('click', function()
{
    if (detectChange() && confirm('Are you sure you want to reset?'))
        form.reset();
});
<form>
  <input type="number" placeholder="Insert a number">
  <input type="number" placeholder="Insert a number">
  <input type="number" value="7" placeholder="Insert a number">
  <button type="button">Reset</button>
</form>


1
我们将使用一些数组方法和特性,例如Array.some()和Spread Syntax。但是,我们真的需要吗?为什么不直接使用以下代码:if (input.value != input.defaultValue || form.querySelectorAll('input:invalid').length)DEMO - user4351667
@Mike 不需要,你已经自己证明了。不过我使用“they”感觉很舒适。 - Shidersz

1

改变这个:

<button type="button">Reset</button>

TO

<input type="reset" value="Reset"/>

通常应该避免在表单中包含重置按钮。它们很少有用,相反更有可能会让用户因错误点击它们(通常是在试图点击提交按钮时)而感到沮丧。 - Mori
@Mori,但是该通知并没有特别指明输入type=reset。它是指重置按钮的一般情况。无论你如何操作,它仍然是一个重置按钮,而且“很少有用,反而更容易让误点的用户感到沮丧”。 - Sebastian Kaczmarek
1
@SebastianKaczmarek:确认对话框可以防止表单被意外重置。 - Mori

0
循环遍历输入字段并手动设置值 = "";

var form = document.querySelector('form');

function detectChange() {
  var inputs = form.querySelectorAll('input');
  for (var input of inputs) {
    input.value = "";
  }
}

form.querySelector('button').addEventListener('click', function() {
  if (confirm('Are you sure you want to reset?')) {
    detectChange(); 
  }
});
<form>
  <input type="number">
  <input type="number">
  <button type="button">Reset</button>
</form>


按钮应该只在有值时才能工作。(非空输入字段) - Mori
@Mori,这个问题实际上在你的问题中没有提到。 - Syed Mehtab Hassan
@Mori 如果在输入标签中粘贴了非数字字符,它不会将其作为值接受。您可以通过使用document.getElementsBytagName('input')进行检查。 - Syed Mehtab Hassan
这无法将值设置为<input type="number" value="87">中的重置(87)值。 - Mark Schultheiss

0

只需使用 button type="reset",并在 form 上附加一个监听器来监听 reset 事件。

你的代码的主要问题是,如果你请求值,浏览器将始终返回空字符串,因为规范对于任何非数字输入都会返回空字符串。这是规范要求的。请参考 https://dev59.com/cGMk5IYBdhLWcg3w6yHh#18853513

解决此问题最初是由 @naga - elixir - jar 提出的建议。我编辑了我的答案,a) 使其成为可行的答案,b) 以简洁、ES6 的方式将其整合在一起。

const form = document.querySelector('form');

form.addEventListener('reset', (event) => {
  if (detectChange() && !confirm('Are you sure you want to reset?')) {
    event.preventDefault();
  }
});

function detectChange() { 
  return [...form.querySelectorAll('input')].some(el => el.validity.badInput || el.value !== el.defaultValue); 
};
<form>
  <input type="number" value="87">
  <input type="number">
  <button type="reset">Reset</button>
</form>


@MarkSchultheiss已添加了关于此问题的解释(和解决方法)。 - connexo
1
一个小提示:如果您在一个输入框中输入了内容,然后使用 backspace 键删除所有字符,确认对话框仍然会触发。但是,我不确定原帖作者是否希望此情况触发确认对话框(毕竟,输入框中确实有一些更改)。 - Shidersz
@Shidersz:“我不确定OP是否希望此情况触发确认对话框。” 只有在有值时,最好是实际值:数字,确认对话框才应该出现。 - Mori
@Mori 所以希望在表单只有空值或无效值的情况下,确认对话框不会出现? - connexo
没问题,可以。 - Mori
显示剩余2条评论

0
只需为输入元素设置 onkeydownonpaste 的事件监听器即可:
const inputs = document.querySelectorAll('input[type=number]')
inputs.forEach((el) => el.onkeydown = el.onpaste = (event) => event.target.dataset.receivedEntry = 1)

然后在 detectChange 中检查 input.dataset.receivedEntry

function detectChange () {
  const inputs = form.querySelectorAll('input');
  for (var input of inputs) {
    if (input.dataset.receivedEntry) {
      return true;
    }
  }
}

@MarkSchultheiss 只需将事件监听器添加到输入框的 onpaste 事件上即可。(已更新答案) - webgodo

-1

var form = document.querySelector('form');
var btn = form.querySelector('button');
var inputs = form.querySelectorAll('input');
btn.disabled = true;
btn.addEventListener('click', function() {
  if (confirm('Are you sure you want to reset?')) {
    form.reset();
    btn.disabled = true;
  }
});

for (var input of inputs) {
  input.addEventListener('keypress', detectSpace)
  input.addEventListener('input', handleChange);
}

function handleChange(e) {
  var disabled = true;
  for (var input of inputs) {
    input.value = input.value.trim()
    if (input.value) {
      disabled = false
    }
  }
  btn.disabled = disabled
}

function detectSpace(e) {
  if (e.keyCode == 32) {
    e.preventDefault();
    return false
  }
}
<form>
  <input type="number">
  <input type="number">
  <button type="button">Reset</button>
</form>

这个会起作用吗?它通过修剪input type="number"内的值来防止用户粘贴数字。

detectSpace是因为在Firefox中,按空格键会删除数字,因为它不是有效的数字。


这会阻止输入一个带有指数符号“1e4”的有效数字,例如。 - Mark Schultheiss
@MarkSchultheiss 它在Chrome和Firefox中都可以工作,甚至包括'1e4'。Firefox将其转换为10000。 - fila90
我使用 Chrome 尝试输入 3e2,但无法输入指数符号“e”。当我按下“e”键时,它会清除该字段。 - Mark Schultheiss

-1
<form>
  <input type="number">
  <input type="number">
  <button type="button" onclick="resetData()">Reset</button>
</form>


function resetData(){
    var y = document.querySelectorAll('input,textarea');
        for (var i= 0; i < y.length; i++) {
        var id =y[i].id;
        if(y[i].value !=''&&y[i].value!= 'undefined'){
        document.getElementById(id).value="";
        }
        } 
}

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接