There is a learning curve associated with my transition from Drupal to a microservice architecture with the front-end application in Svelte / Sapper. This article explains shows some of the structure of Svelte components and explains some of the issues I ran into when using Svelte.

Finding my way around Svelte

The Svelte technology stack is new and changes frequently, this often included breaking backward compatibility. Not being able to use examples from the recent past (2018) in StackOverflow and from the issues is one of the major learning obstacles.

For example, you could use ref:name in the past to bind variables but it is deprecated and no longer works in favor of the bind: syntax. Luckily, these breaking changes are documented in this repository. Which is mandatory reading for anyone that wants to try out Svelte just so you can understand the examples from Svelte 2. Another example is that the way you define and call javascript function has changed. We use the correct method in this article.

The biggest resource, besides the docs, for help is the Svelte Discord channel mainly kudos for antony and Conduitry for answering (my) questions very actively. The testing suite (Sapper) is another great up-to-date collection of examples which you can use during daily development. Furthermore, this repository seems also to be updated and contains a more realistic example.

Signup Form

Ok, let’s see some code! We assume you use something like the Sapper template to setup your project. First, we create a new Svelte component called Signup.svelte and put in a basic HTML Signup Form.

<form>
  <label for="email">Email</label>
  <input required type="email" id="email" />

  <label for="password">Password</label>
  <input required type="password" id="password" />
  
  <button type="submit">Create account</button>
</form>

Then, include the component in a page using by importing it with and adding it to the page with:

import Signup from '../components/Signup.svelte'
...
<Signup/>

You should now see a form on the page.

Submit behavior

When you fill in the fields and click the button it will refresh the page which is the default behavior for forms in HTML. To do this, we need to define a function and change the default behavior by using the on: syntax.

<script>
   async function handleSubmit(event) {
        console.log(event);
        console.log(event.target);
        console.log(event.target.email.value);
        console.log(event.target.password.value);
    }
</script>

<form on:submit|preventDefault="{handleSubmit}" >

Now, when clicking on the submit button the page will not reload and we will get a log of the event object and its target (the form). From here we can derive the filled-in email and password. From here you can do something with the submission, for example, calling an authentication microservice like this (more on this in a future article):

// Call an authenication microservice to handle the authentication.
const response = await fetch("/signup",
{
method: 'POST',
headers: {
'Accept': 'application/json',
'Content-Type': 'application/json'
},
body: JSON.stringify({email: email, password: password})
});
const data = await response.json();

Customize HTML5 validation

Note that we added HTML validation with specifying the types of the field (email and password). This allows the browser to validate the input. Unfortunately, this input is notoriously difficult to adjust but Svelte does make it easy. We can use the same on: syntax to adjust the default validation. For example, take a look at this code to change the validation message. Code is based on the solution by Rikin Patel.

   function validateMessageEmail(event) {
       let textbox = event.target;
       if (textbox.value === '') {
            textbox.setCustomValidity('Required email address');
        } else if (textbox.validity.typeMismatch){
            textbox.setCustomValidity('please enter a valid email address');
        } else {
           textbox.setCustomValidity('');
        }
        return true;
    }
</script>

<form 
    on:submit|preventDefault="{handleSubmit}"
    on:invalid={validateMessageEmail}
    on:changed={validateMessageEmail}
    on:input={validateMessageEmail}
>

Binding objects

To customize the form more we can easily make custom error messages using bindings. First, let’s create the variable and change the function:

<script>
    let error_boolean = false;

   ...
   function validateMessageEmail(event) {
       ...
       error_boolean = false;
        ...
        } else if (textbox.validity.typeMismatch){
            error_boolean = true;
...

Now, we can use this variable in the HTML to add a big H1 error during HTML5 validation.

<input required type="email" id="email" />
{#if error_boolean}
  <h1> OH NO! AN ERRROR!</h1>
{/if}

You should now have the general tools to customize your forms to your desire

Meaning wave

Shout out to Akira the Don for creating this “meaning wave” music which works well for me to listen to during development. Some of my favorite tunes:

Full tutorial code for reference

<script>
    let error_boolean = false;

   async function handleSubmit(event) {
       console.log(event);
       console.log(event.target);
       console.log(event.target.email.value);
       console.log(event.target.password.value);
    }

   function validateMessageEmail(event) {
       let textbox = event.target;
       error_boolean = false;
       if (textbox.value === '') {
            textbox.setCustomValidity('Required email address');
        } else if (textbox.validity.typeMismatch){
            error_boolean = true;
            textbox.setCustomValidity('please enter a valid email address');
        } else {
           textbox.setCustomValidity('');
        }
        return true;
    }
</script>

<form
    on:submit|preventDefault="{handleSubmit}"
    on:invalid={validateMessageEmail}
    on:changed={validateMessageEmail}
    on:input={validateMessageEmail}
>
  <label for="email">Email</label>
  <input required type="email" id="email" />
  {#if error_boolean}
    <h1> OH NO! AN ERRROR!</h1>
  {/if}

  <label for="password">Password</label>
  <input required type="password" id="password" />

  <button type="submit">Create account</button>
</form>

0 Comments

Leave a Reply

Avatar placeholder

Your email address will not be published. Required fields are marked *