Here's a quick implementation of Svelte's handy custom events system.
Background
Our users can edit any part of their profile using a dynamic modal editor component.
User Story
As a user editing my profile, I want to be able to Publish or Cancel when editing any of my profile modules.
Engineering Requirements
- Make the Save and Cancel button a reusable component
- Let each component handle the save event because they have unique business logic
- Let the modal component handle the cancel event
Solution
The first step is to build an EditActionsBar.svelte that is responsible for displaying the Publish and Cancel buttons.
By importing createEventDispatcher
, I can dispatch semantic events that make it really clear what the action is, instead of the generic on:click
event.
// EditActionBar.svelte
<script>
import { createEventDispatcher } from 'svelte';
const dispatch = createEventDispatcher();
let save = function(e) {
dispatch('save');
}
let cancel = function(e) {
dispatch('cancel');
}
</script>
<div class="flex flex-row justify-between mt-10">
<button on:click|preventDefault={cancel} class="cursor-pointer bg-gray-300 rounded-full px-8 py-4">
Cancel
</button>
<button on:click|preventDefault={save} class="cursor-pointer bg-purple-700 text-white rounded-full px-8 py-4">
<i class="fas fa-check mr-2" /> Publish Changes
</button>
</div>
This can now be dropped into any of our editor components. We simply forward the on:cancel
event and handle the on:save
event.
<EditActionsBar on:save={save} on:cancel></EditActionsBar>
For example, this is how we could add it to a simplified version of our EditProfileBody.svelte file.
// EditProfileBody.svelte
<script>
import service from '$lib/_services/users.service';
import TextInput from '$lib/_shared/forms/large/TextInput.svelte';
import TextArea from '$lib/_shared/forms/large/TextArea.svelte';
import EditActionsBar from './EditActionsBar.svelte';
// handlers
let save = async (e) => {
const res = await service.editProfile({
headline,
description
});
};
</script>
<h2 class="text-lg font-medium mb-2">Edit Intro</h2>
<div class="flex flex-col gap-4 mt-8">
<TextInput
bind:value={headline}
name="headline"
label="Headline"
/>
<TextArea
bind:value={description}
name="description"
label="Description"
/>
<EditActionsBar on:save={save} on:cancel></EditActionsBar>
</div>
Conclusion
If you found this format helpful, let me know in the comments or on Twitter @jmzaborowski.