
Join the Conversation!
Subscribing gives you access to the comments so you can share your ideas, ask questions, and connect with others.
"Please login to view comments"
Subscribing gives you access to the comments so you can share your ideas, ask questions, and connect with others.
Complete source code for this lesson is available at
By logging in, you'll unlock full access to this and other free tutorials on JSM Pro.
Why? Logging in lets us personalize your learning experience, track your progress, and keep you in the loop with new workshops, coding tips, and platform updates.
You'll also be the first to know about upcoming launches, events, and exclusive discounts.
No spam—just helpful content to level up your skills.
If that sounds fair, go ahead and log in to continue →
Enter your name and email to get instant access
##Looks like we found a thief monkey By the way, I liked the trick how you reached till here. You have a good sense of humor. You will improve a lot if you join our course with this passion.
var
(function-scoped, outdated)let
(block-scoped, modern and recommended)const
(block-scoped, cannot be reassigned)_
, or $
let let = 5;
is invalid)myVar
and myvar
are different)string
, number
, boolean
, null
, undefined
, bigint
, symbol
Objects
, Arrays
, Functions
Subscribing gives you access to a brief, insightful summary of each lecture to stay on track.
00:00:02 Now it's time to get all the answers associated with the question so that we can display them right here on the UI.
00:00:09 To do that, we'll have to create a server action called getAnswers that has all sorts of different sorts and filters.
00:00:16 So head over into actions, answer.action.ts, and we'll do it right below createAnswer.
00:00:22 But as usual, let's first create the validation and all the types needed for the server action.
00:00:28 So first head over into the action.d.ds and create a new interface called get answers params.
00:00:39 And that'll actually extend paginated search params, but now with one additional param called question ID, which will be of a type string.
00:00:51 And then we can head over into the validations.ts and right below, we can do a similar thing by saying export const get answers schema.
00:01:02 And it'll be equal to paginated search program schema.extend.
00:01:08 And we'll extend it with a question ID, which will be of a type z.string with a min of one character, meaning that it's required.
00:01:16 Alongside that, since we'll be showing these answers on the UI with its user details, let's also create a global answer type in global.d.ts.
00:01:26 See how we have this question here?
00:01:28 Well, now we'll have an answer too.
00:01:31 So let's scroll all the way down.
00:01:33 And let's create another interface called answer.
00:01:36 And it'll have an underscore ID of a type string, an author of a type author, since we already have an interface of the author,
00:01:45 which has the ID name and the image.
00:01:47 It'll also have a content, which will be of a type string.
00:01:51 And finally, it'll have a created ad property of a type date.
00:01:56 Now let's use all of these to create our getAnswers server action.
00:02:00 So we can continue right where we left off in the answerActionTS right below the createAnswer.
00:02:07 Let's export a new async function.
00:02:12 called getAnswers.
00:02:13 And the first param will be params of a type getAnswers params.
00:02:20 And the return of the function will be a promise of the action response.
00:02:26 Specifically, it'll return an object that has access to answers of a type.
00:02:32 AnswerArray is next property to know whether more answers exist.
00:02:37 That'll be a boolean.
00:02:39 And the number of total answers, which of course will be a number.
00:02:43 Finally, we can close that type and once more, and we can open up a function block.
00:02:50 That'll look something like this once ESLint and Prettier formatted nicely.
00:02:55 It'll be red right now.
00:02:56 because right now we're not returning what we said we would return, but we'll do that very soon.
00:03:02 Let's first get access to the validation result by making it equal to await our all-powerful action.
00:03:10 And to it, we can pass over the params as well as the schema of the getAnswers schema coming from the validations.
00:03:19 Next, we can check if a validation result is an instance of error In that case, we can return the handle error call with the validation result passed in
00:03:29 as the error response.
00:03:30 But if we don't have an error, then we can start destructuring some things from the params, such as the question ID we're trying to fetch the answers for,
00:03:39 the page of those answers as well as the page size, meaning how many we want to show on the page at once.
00:03:46 And we're getting those from the params we're passing in.
00:03:49 I'm also providing some default values for the page and the page size of 1 and 10 respectively.
00:03:55 Next, let's implement the pagination by figuring out how many elements we want to skip.
00:03:59 So we can say skip is equal to.
00:04:02 I'll wrap it in parentheses and then wrap the page with a number.
00:04:07 decrement 1, and then multiply it by page size.
00:04:12 What this will do is it'll give us the number of elements we want to skip, so it'll take the current page we're on, decrement by 1, and then multiply it
00:04:19 by the page size.
00:04:21 Finally, we also want to set the limit to be equal to the page size.
00:04:26 Once we do that, we can create a new object called sort criteria.
00:04:32 And to the start, it'll be equal to an empty object.
00:04:35 But then as we turn on specific sorting and filtering options or turn them off, we'll be able to modify it.
00:04:42 So let's open up a switch statement.
00:04:45 that I look into the value of a filter, and if the filter case is equal to latest, in that case, we will change the sort criteria to be equal to created
00:05:00 at minus one.
00:05:01 And where is this filter coming from?
00:05:03 Well, we'll also filter and sort everything through query params.
00:05:07 So we can accept it right here from the top.
00:05:09 Alongside sorting by the latest, we can sort by the oldest.
00:05:13 So let's say oldest, and it'll just be reversed, sort criteria created at one.
00:05:19 We can also sort it by case of popular, where the sort criteria will be upvotes minus one.
00:05:26 So the ones that have the most upvotes.
00:05:28 And by default, we can do sort criteria created at minus one.
00:05:32 Finally, now that we have our pagination and sorting and filtering done, we are ready to fetch those answers.
00:05:39 So let's open up a new try and catch block.
00:05:43 In the error, we can simply return a handle error as error response.
00:05:48 And in the try, we can try to get the total number of all the answers.
00:05:52 This will help us with the pagination.
00:05:54 So I'll say total answers is equal to.
00:05:58 await answer.countDocuments where the question is equal to the question ID that we want to get the answers for.
00:06:06 After that, we can get the actual answers by saying const answers is equal to await answer.find.
00:06:13 And once again, give me the answers that belong to this specific question.
00:06:18 And for each answer, Populate the author information, specifically give me the underscore ID, the name, and the image.
00:06:29 This is super useful because then we can know which user posted that actual answer.
00:06:34 Let's also run the dot sort and sort it based on the sort criteria.
00:06:39 Let's skip a specific number of elements and let's limit it to a specific number of elements as well.
00:06:46 We already have created all the variables for what we need right here.
00:06:50 Once we do that, we can figure out if the next page exists.
00:06:54 And we can do that by comparing the number of the total answers.
00:06:58 And if that number is greater than skip times the limit, we can figure out if the next page exists by saying const is next.
00:07:07 And we make a comparison with the number of the total answers.
00:07:12 And if that number is greater than the skip amount plus the answers.length, which means that there are more answers than we're currently returning.
00:07:22 If that is the case, then the next page exists.
00:07:25 Finally, let's fix this typo right here.
00:07:27 This is not supposed to say popular author.
00:07:30 It's supposed to say populate author.
00:07:33 And then we can return an object where the success property is set to true.
00:07:38 And the data will be equal to an object that contains the answers where we can just JSON parse it and JSON stringify it as always to get it to our front end.
00:07:50 We can pass over the isNext property and the total number of answers.
00:07:55 And that's it.
00:07:56 That is our get answers server action.
00:07:59 So to see whether this is working properly, let's head over into our question details page.
00:08:04 That is the ID page of the questions.
00:08:07 And let's call it right at the top.
00:08:09 Right after we make a check whether a question even exists, we can start fetching the answers.
00:08:15 const we will destructure something and make it equal to await get answers and this is a call to our server action to it we have to pass all the different
00:08:28 programs and you already know what those programs are right it's the question ID which in this case will be equal to just ID since we're on the question
00:08:36 details page What else do we have to pass into the getAnswers?
00:08:40 Well, we can take a look at the getAnswers params.
00:08:43 It seems like it's only the question ID, but we're actually extending the paginated search params, which have many optional parameters for search and filtering.
00:08:54 So we can pass the current page number, the total page size, the search query, filtering or sorting options.
00:09:01 So if those exist, let's go ahead and pass them.
00:09:04 So let's pass a page of one, and a page size of 10. Of course, feel free to modify it however you like.
00:09:11 And I'll filter it by the latest.
00:09:15 Now, what do we get back?
00:09:17 Well, of course, we get back a success status.
00:09:20 We also get back the data and we get back the error information.
00:09:26 Now, you can notice that this success has the same variable name as our get question and same thing happens with the data right here.
00:09:34 So let's rename success to R answers loaded and let's rename the data to answers result.
00:09:43 And let's rename the error to answers error.
00:09:49 That way we know exactly what we're talking about.
00:09:52 And for now, we can simply console log answers and then we can render the answer result and see what we get back.
00:09:59 I'll reload the page and open up my terminal and take a look at this.
00:10:03 We get back the answers result, which contains the answer data, which has an answer to this question.
00:10:09 There's only one answer and there are no other pages.
00:10:12 What if we go to a second question?
00:10:14 This one has no answers.
00:10:16 So the console log is pretty slim.
00:10:18 Great.
00:10:19 Now that we know that the data is being logged, We can go ahead and save that by saying something like implement get all answers action,
00:10:27 commit it and sync it.
00:10:29 And then in the next lesson, we can go ahead and display those answers right here within question details.