在我的页面上有多个表单会触发意想不到的行为



我在我的页面上有多个表单,每个表单都有不同的id(从数据库动态填充),我尝试使用JavaScript替换一些类,并在上传后动态添加文件名。

我不知道为什么即使id是完全唯一的,我得到一个奇怪的行为:无论我提交文件的形式是什么,JavaScript将应用更改总是在第一个。

我有我的JavaScript代码附加在每个表单的相同的div之后的</form>关闭标签。

function spinnerLoad(){
document.getElementById('file-name[[${id}]]').textContent = this.files[0].name;

document.getElementById('spinner[[${id}]]').classList.replace('fas', 'spinner-border');
document.getElementById('spinner[[${id}]]').classList.replace('fa-file-upload', 'spinner-border-sm');
document.getElementById('uploadForm[[${id}]]').submit()
}

我使用Bootstrap作为样式规则。

/*${id} variable is server-side and it's there to make unique each form, I'm using Thymeleaf template engine*/
<form th:id="'uploadForm'+${id}" method="post" enctype="multipart/form-data" th:action="@{/upload/{id} (id=${id})}">
<label for="file-upload" class="btn btn-outline-success">
<span th:id="'spinner'+${id}" class="fas fa-file-upload"></span> <b>Upload file:</b> <i th:id="'file-name'+${id}">No file selected</i>
</label>
<input id="file-upload" type="file" name="multipartFile"  accept="application/pdf" style="display: none" th:onchange="spinnerLoad()"/>
</form>

我在谷歌上搜索了一下,但没有找到我问题的具体答案。

如果你想自己测试这个代码片段,你可以用任何你喜欢的数字代替${id},它必须是唯一的。当然,你必须用至少2个不同的表单来测试它。

您没有向我们展示如何处理表单,每个表单都有不同的id"所以我使用了以下假设:

在我的Java代码中,我使用以下代码(假设是普通的thymleaf):

model.put("id_a", "123");
model.put("id_b", "456");

或者,如果这是一个基于spring的应用程序,可能是:

model.addAttribute("id_a", "123");
model.addAttribute("id_b", "456");

但在这两种情况下,这是我们定义唯一id的地方-每个HTML表单一个。model是我们将这些变量传递给thymleaf模板的方式,以通常的方式。

然后,在Thymeleaf模板中我们有如下内容:

<body>
<form th:id="'uploadForm'+${id_a}" 
method="post" 
enctype="multipart/form-data" 
th:action="@{/upload/{id_a} (id=${id_a})}">
<label for="file-upload" class="btn btn-outline-success">
<span th:id="'spinner'+${id_a}" 
class="fas fa-file-upload">
</span> 
<b>Upload file:</b> 
<i th:id="'file-name'+${id_a}">No file selected</i>
</label>
<input id="file-upload" 
th:data-unique-id="${id_a}"
type="file" 
name="multipartFile"  
accept="application/pdf"  
onchange="spinnerLoad(this.getAttribute('data-unique-id'))"/>
</form>
<form th:id="'uploadForm'+${id_b}" 
method="post" 
enctype="multipart/form-data" 
th:action="@{/upload/{id_b} (id=${id_b})}">
<label for="file-upload" class="btn btn-outline-success">
<span th:id="'spinner'+${id_b}" 
class="fas fa-file-upload">
</span> 
<b>Upload file:</b> 
<i th:id="'file-name'+${id_b}">No file selected</i>
</label>
<input id="file-upload" 
th:data-unique-id="${id_b}"
type="file" 
name="multipartFile"  
accept="application/pdf"  
onchange="spinnerLoad(this.getAttribute('data-unique-id'))"/>
</form>
<script>
function spinnerLoad(id) {
console.log(id);
document.getElementById('file-name' + id).textContent = this.files[0].name;
document.getElementById('spinner' + id).classList.replace('fas', 'spinner-border');
document.getElementById('spinner' + id).classList.replace('fa-file-upload', 'spinner-border-sm');
document.getElementById('uploadForm' + id).submit()
}
</script>
</body>

每个表单使用自己唯一的ID -${id_a}${id_b},并且只有一个spinnerLoad()函数。函数调用方式为:

onchange="spinnerLoad(this.getAttribute('data-unique-id'))"

this.getAttribute('data-unique-id')的值为th:data-unique-id="${id_a}"th:data-unique-id="${id_b}"提供的值。

因此,传递的参数将是123456。然后spinnerLoad函数将对正确的元素进行操作。

上述技术在我链接到的答案中有描述。

你问:

如果我把我的JavaScript代码放到:onchange="/JavaScript代码这里/"不使用函数名?

不,出于安全原因,您不能这样做,以避免执行包含用户提供(因此可能不安全)数据的任意代码。这实际上是答案中该技术的全部要点——为该限制提供一个安全的解决方案。


其他说明:

如果你不想有多个单独的<form>HTML块,你可以在JavaList中提供你唯一的id,并在Thymeleaf中迭代列表——类似于这个文档示例中构建表行的方式。

正如在注释中所指出的,您可以用事件处理程序替换onchange="spinnerLoad(this.getAttribute('data-unique-id'))"属性—但就如何处理惟一id而言,这基本上与上面所示的基本方法相同。

最新更新