![](/style/images/good.png)
![](/style/images/bad.png)
Building a Full Stack Application From Scratch with Svelte and Node (PART 4) — A...
source link: https://tahazsh.com/fullstack-app-with-svelte-and-node-part-4
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.
In the previous part, we displayed comments and replies in the story page. Now let's add the needed inputs for users to create them.
Creating CommentInput component
This component will be responsible for displaying the comments form and submitting it to the server to save it in the database (which we'll do later).
Create routes/story/_CommentInput.svelte, and put the following into it:
<script>
let comment = {
content: '',
parent: null
}
function submit () {
console.log('form is submitted')
}
</script>
<form
class="comment-form"
on:submit|preventDefault="{submit}"
>
<textarea
class="comment-input"
bind:value="{comment.content}"
placeholder="Write your comment"
required
></textarea>
<button
class="add-comment-button primary-button"
>
Add Comment
</button>
</form>
As you can see above, we're binding comment.content
to the textarea, and when it's submitted, we call the submit()
function.
Since this input creates a comment, not a reply, we sat the comment.parent
to null
.
Submitting the form
When this form is submitted, we'll make a request to the server with its content so the server will create it, persist it, and return it back to the client to display it.
Since we don't have the server yet, let's mock that behavior and just return it with some test values.
Now let's update the submit
function to this:
function submit () {
// this should eventually be returned from the server
const newComment = {
score: 0,
_id: Math.round((Math.random() * 99999)),
content: comment.content,
user: {
username: 'test user',
},
createdAt: 'a few seconds ago',
replies: []
}
dispatch('created', { comment: newComment })
comment = {
content: '',
parent: null
}
}
So after the server returns the comment, we should pass it back to the parent component (_CommentContainer.svelte) so it appends it to the list of displayed comments.
We're using dispatch
to send it back to _CommentContainer, but for that to work, we have to import the dispatcher first.
So at the top of this file, add this:
<script>
import { createEventDispatcher } from 'svelte'
const dispatch = createEventDispatcher()
Displaying _CommentInput in _CommentContainer
First, import that component:
import CommentInput from './_CommentInput.svelte'
Then, display it above <div class="comment-list">
.
<CommentInput
on:created="{({ detail }) => comments = [...comments, detail.comment]}"
/>
We're here listening for the created
event, which we sent from the submit
function, to add that comment to the list of comments we're displaying.
Now it's time to test your work. You should see the comment input displayed like this:
![1.png](https://api.tahazsh.com/images/fullstack-app-with-svelte-and-node-part-4/1.png)
Creating ReplyInput component
This component is for the reply input that we show under a specific comment.
We should show a "reply" button besides each comment. When the user clicks it, we should show that input below it.
Before we add that "reply" button, let's create the reply form.
Create routes/story/_ReplyInput.svelte with the following code:
<script>
import { createEventDispatcher } from 'svelte'
const dispatch = createEventDispatcher()
export let parentCommentId
let comment = {
content: '',
parent: parentCommentId
}
async function submit () {
const newComment = {
score: 0,
_id: Math.round((Math.random() * 99999)),
content: comment.content,
user: {
username: 'test user 2',
},
createdAt: 'a few seconds ago',
replies: []
}
dispatch('created', { comment: newComment })
}
</script>
<form
class="reply-form"
on:submit|preventDefault="{submit}"
>
<textarea
class="reply-input"
bind:value="{comment.content}"
></textarea>
<div class="reply-buttons-container">
<button
type="button"
class="cancel-reply-button text-button"
on:click="{() => dispatch('cancel')}"
>
Cancel
</button>
<button
class="reply-button primary-button"
>
Reply
</button>
</div>
</form>
It's like the comment input but with two differences:
- We're accepting a prop called
parentCommentId
which we use for theparent
value for the reply. That value should be the comment id the user is replying to. - We dispatch a
cancel
event when the cancel button is clicked. This event is to close the reply form without submitting it.
Displaying the reply input
This component should be displayed inside the _Comment component. And it should only be displayed if the "reply" button is clicked.
Add the following code in _Comment.svelte above {#if comment.replies && comment.replies.length}
:
{#if showReplyForm}
<ReplyInput
parentCommentId="{comment._id}"
on:created="{addReply}"
on:cancel="{() => showReplyForm = false}"
/>
{/if}
And don't forget to import it at the top:
import ReplyInput from './_ReplyInput.svelte'
Note how we're passing the parent comment id through parentCommentId
.
We need to do two more changes to make this component work:
- Create the "reply" button that toggles the
showReplyForm
value. - Add and implement the
addReply
function.
Let's start with the "reply" button.
Update the <div class="main">
element like this:
<div class="main">
<div class="byline">
<span class="author">{comment.user.username}</span>
<span class="date">{comment.createdAt}</span>
<span
class="show-reply-form-button"
on:click="{() => showReplyForm = true}"
>reply</span>
</div>
<p class="comment-content">{comment.content}</p>
</div>
This element now contains the "reply" button, which if you click, showReplyForm
will be set to true
.
Next, let's create that variable below export let comment
:
let showReplyForm = false
Our last step is to create addReply
function, which we trigger on the created
event on the ReplyInput
component.
function addReply ({ detail }) {
comment.replies = [...comment.replies, detail.comment]
showReplyForm = false
}
It looks similar to how we add a new top-level comment except that we set showReplyForm = false
to close it after that.
Posting a reply to any comment should now work!
![2.png](https://api.tahazsh.com/images/fullstack-app-with-svelte-and-node-part-4/2.png)
What's next?
In the next part, we'll implement the story form component for creating and editing stories. We'll learn how to make that component reusable for both create and edit story pages. It's a great way to keep your code DRY and clean.
Recommend
About Joyk
Aggregate valuable and interesting links.
Joyk means Joy of geeK