javascript - 使用 API (Rails) 中的 Svelte 正确处理错误
问题描述
我正在开发一个与 Rails API 服务器通信的 Svelte 前端应用程序。我喜欢 Rails 的抽象方式(尤其是 simple_form gem),我想为 Svelte 带来一些想法。我遇到的特殊问题是如何将来自 rails 服务器的错误与苗条端的输入相关联
首先,我调整了来自服务器的错误响应;一般来说,它们看起来像这样:
{ errors:
{ generic: [<messages without association with particular field>],
email: ["Already taken", <msg_2>, ...],
password: ["Too short", ...],
field_N: [...]
}
}
一般错误可以是“无效的登录凭据”、“您的帐户被锁定”、“内部服务器错误”等。其他错误必须与表单字段相关,并且必须显示在它们旁边。
这是我目前的方法signup.svelte:
<script>
let email;
let password;
function registerRequest() {
let regURL = baseURL+'/api/users/';
let data = {"user": {"email": email, "password": password}};
fetch(regURL, {
method: 'POST',
body: JSON.stringify(data),
headers: {
'Content-Type': 'application/json'
}
})
.then(function(response) {
if (!response.ok) {
return response.json()
}
})
// if errors present then iterate through errors object
.then(function(error) {
// find id of the message field and insert actual messages
for (let [key, value] of Object.entries(error.errors)) {
document.getElementById(key).insertAdjacentHTML('beforeend',value);
}
});
}
</script>
<style> .errormessage { color: red; } </style>
<form class="col-sm-12 col-lg-6" on:submit|preventDefault={registerRequest}>
<!-- here I need to create errormessage container for each field. -->
<!-- first one is generic to display generic errors -->
<div class="errormessage" id="generic"></div>
<label for="UserEmail">Email address</label>
<input type="email" class="form-control" id="UserEmail" aria-describedby="emailHelp" placeholder="Enter your email here..." bind:value={email}>
<div class="errormessage" id="email"></div>
<label for="UserPassword">Password</label>
<input type="password" class="form-control" id="UserPassword" placeholder="...and your password here" bind:value={password}>
<div class="errormessage" id="password"></div>
<button type="submit" class="btn btn-primary">Register</button>
</form>
我想将上面的代码与前端验证统一起来。如果errors
对象出现 - 在有错误的字段旁边显示消息。在我看来,使用getElementById
是矫枉过正。如果我的 DOM 从不重新加载,我为什么要使用它?每次input
它都会搜索ID。也许应该是监听器来监听错误对象的变化?我试图将自定义event
与 Svelte
绑定import { createEventDispatcher } from 'svelte';
,但没有运气。
请帮助并分享您的想法。
解决方案
您的直觉是正确的,getElementById
在 Svelte 组件中使用会让人感觉不舒服 - 通常 Svelte 希望您让您的代码具有声明性,其中 DOM 是状态的函数,而不是您手动更改 DOM 的命令。
对于错误消息,我建议errors
在您的组件中添加一个变量。当服务器错误再次出现时,您可以将它们分配给errors
,这将导致响应式更新并重新渲染组件。然后,标记可以知道在错误存在时呈现错误,而无需显式更改 DOM。像这样的东西:
<script>
let email;
let password;
// New `errors` variable.
let errors = {};
function registerRequest() {
// Reset the errors when the user submits a new request.
errors = {};
let regURL = baseURL+'/api/users/';
let data = {"user": {"email": email, "password": password}};
fetch(regURL, {
method: 'POST',
body: JSON.stringify(data),
headers: {
'Content-Type': 'application/json'
}
})
.then(function(response) {
if (!response.ok) {
return response.json()
}
})
.then(function(error) {
// Just save the errors
errors = e.errors;
});
}
</script>
<style> .errormessage { color: red; } </style>
<form class="col-sm-12 col-lg-6" on:submit|preventDefault={registerRequest}>
<!-- first one is generic to display generic errors -->
<!-- note the `|| []` part, which makes sure that
`#each` won't throw an error when `errors.generic` doesn't exist -->
{#each (errors.generic || []) as error}
<div class="errormessage" id="generic">{error}</div>
{/each}
<label for="UserEmail">Email address</label>
<input type="email" class="form-control" id="UserEmail" aria-describedby="emailHelp" placeholder="Enter your email here..." bind:value={email}>
<!-- email errors -->
{#each (errors.email || []) as error}
<div class="errormessage" id="email">{error}</div>
{/each}
<label for="UserPassword">Password</label>
<input type="password" class="form-control" id="UserPassword" placeholder="...and your password here" bind:value={password}>
<!-- password errors -->
{#each (errors.password || []) as error}
<div class="errormessage" id="password">{error}</div>
{/each}
<button type="submit" class="btn btn-primary">Register</button>
</form>
这是一个Svelte REPL,该代码可以正常工作。希望有帮助!
推荐阅读
- ajax - 使用 Bokeh AjaxDataSource 发出凭据请求
- c - 为什么页面错误和不可恢复的错误需要不可屏蔽?
- angular - 使用 Angular 使用以前的地址自动完成表单
- database - 向数据库列添加注释并从 AWS Glue 检索
- angular - 将拍摄的照片移动到另一个组件
- express - 如果不满足条件,则拒绝 PUT 请求
- php - Laravel 抛出 Route [/profileUpdate/update] 未定义错误
- websocket - 将 Cypress 与“模拟套接字”一起使用
- java - 为什么 `parallelStream` 比 `CompletableFuture` 实现更快?
- ms-access - 访问:如何在设计视图中将所有字段添加到查询