我正在开发一个Svelte前端应用程序,该应用程序与Rails API服务器进行通信。我喜欢Rails的抽象方式(尤其是使用simple_form gem),并且希望为Svelte带来一些想法。我遇到的特定问题是如何将来自Rails服务器的错误与苗条的输入相关联]
首先,我从服务器调整了错误响应;通常,它们看起来像这样:
{ errors:
{ generic: [<messages without association with particular field>],
email: ["Already taken", <msg_2>, ...],
password: ["Too short", ...],
field_N: [...]
}
}
generic错误可以是“无效的登录凭据”,“您的帐户被锁定”,“内部服务器错误”等。其他错误必须与表单字段相关,并且必须显示在它们旁边。
这是我目前的做法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';
,但没有运气。
请帮助并分享您的想法。
您的直觉是正确的,在Svelte组件中使用getElementById
会感到不舒服-通常Svelte希望您使代码成为代码[[declarative,其中DOM是状态的函数,而不是imperative您正在手动更改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,该代码正常工作。希望能有所帮助!