![](/style/images/good.png)
![](/style/images/bad.png)
Building a Full Stack Application From Scratch with Svelte and Node (PART 5) — C...
source link: https://tahazsh.com/fullstack-app-with-svelte-and-node-part-5
Go to the source link to view the article. You can view the picture content, updated content and better typesetting reading experience. If the link is broken, please click the button below to view the snapshot at that time.
To create a story, you need to provide a title, a type, and a link or description (based on the type).
Let's start by implementing the form component, and then use that form on the create and edit story pages.
Creating story form
Since we're working on the story section, create _StoryForm.svelte inside the routes/story directory. And then add the following (explained below):
<script>
import { goto } from '@sapper/app'
import ButtonGroup from '../../components/ButtonGroup.svelte'
export let story
let inProgress = false
async function submit () {
inProgress = true
if (story._id) {
console.log('Update story with id', story._id)
} else {
console.log('Create a new story')
}
// redirect to the story you just created/updated
goto(`/story/123`)
}
</script>
<form
class="story-form"
on:submit|preventDefault="{submit}"
>
<input
class="text-input"
bind:value="{story.title}"
type="text"
placeholder="Title"
required
>
<ButtonGroup
bind:value="{story.type}"
disabled="{story._id}"
buttons="{[
{
value: 'link',
title: 'Link'
},
{
value: 'text',
title: 'Text'
}
]}"
/>
{#if story.type === 'link'}
<input
class="text-input link-input content-input"
bind:value="{story.content}"
type="url"
placeholder="URL"
required
>
{:else}
<textarea
class="content-text-input content-input"
bind:value="{story.content}"
placeholder="Text (optional)"
></textarea>
{/if}
<button
class="primary-button submit-button"
disabled="{inProgress}"
>
{#if story._id}
SAVE
{:else}
POST
{/if}
</button>
</form>
Since we're going to use the same form for creation and editing stories, we're accepting story
data as prop.
If story
contains _id
field, then this form is for editing it. Look how we're using this check in:
submit
function: which will either send an update request or a create request.ButtonGroup
component: to disable it if we're in editing page — the user shouldn't be able to change the story type once it's created.- submit button: to either display "SAVE" or "POST" on the button.
Since we don't have our backend server created yet, we're not sending any requests. We're instead logging a message to the console to indicate whether we're updating or creating a story.
The inProgress
variable here is used to disable the submit button when it's currently submitting so we prevent the user from accidentally submitting the form more than once.
After the form has been submitted successfully, we redirect the user to the created/updated story view page. For that, we're using sapper's goto function.
ButtonGroup
is a custom component to allow users to choose a single value from multiple options. (You can use a simple radio button or a dropdown instead, but I found this to look nicer!)
The user can either enter a link or text for a story. So based on the current value of story.type
(which is controlled by ButtonGroup
) we either display a text input for the link or a textarea for the text.
Note how we're importing this component at the top while we don't have it in our project. So let's add src/components/ButtonGroup.svelte with the following code:
<script>
export let buttons = []
export let value
export let disabled = false
</script>
<div
class="button-group"
class:disabled="{disabled}"
>
{#each buttons as button}
<button
class="button"
type="button"
class:active="{button.value === value}"
on:click="{() => !disabled ? value = button.value : ''}"
>
{button.title}
</button>
{/each}
</div>
Adding story create page
Create create.svelte in route/story and add this:
<svelte:head>
<title>Create a new story</title>
</svelte:head>
<script>
import StoryForm from './_StoryForm.svelte'
let story = { title: '', type: 'link', content: '' }
</script>
<StoryForm {story}/>
Since the story
variable doesn't have _id
, the story form will be displayed for creating stories.
Now if you open http://localhost:3000/story/create in your browser, you should see this:
![1.png](https://api.tahazsh.com/images/fullstack-app-with-svelte-and-node-part-5/1.png)
Adding story edit page
The URL for this page would be: /story/123/edit. This means we need create the edit page inside /routes/story/[id]/edit.svelte
. But you may say: "But we already have [id].svelte".
Right, we're using that component for the story view page. So to keep it as that, we can rename it to index.svelte
and move it into [id]
directory.
So create [id]
directory inside routes/story
and rename [id].svelte
to index.svelte
and move it there.
For that to work, we have to fix import paths inside [id]/index.svelte
like so:
<script>
import Story from '../../_components/Story.svelte'
import CommentContainer from '../_CommentContainer.svelte'
</script>
Now we can create our edit page inside [id]
and name it edit.svelte
— so it is src/routes/story/[id]/edit.svelte
.
Next, let's write the following inside edit.svelte
:
<script>
import StoryForm from '../_StoryForm.svelte'
let story = { _id: 1, title: 'Story Title', type: 'link', content: 'https://svelte.dev/' }
</script>
<svelte:head>
<title>Edit your story</title>
</svelte:head>
<StoryForm {story}/>
Note how we're using mocked data for the story
variable. When our backend server is ready, we'll fetch the story from the database using the id in the url.
To test this page, open http://localhost:3000/story/1/edit in the browser. (Note how the button group element is disabled.)
What's next?
Our next part is a quick and easy one. It'll be about creating the nav bar along with the login and signup pages.
Recommend
About Joyk
Aggregate valuable and interesting links.
Joyk means Joy of geeK