0

I have Nuxt.js Hackernews project.
When I get posts from API of Hackernews I do not get sorted posts by time desc.
I need to sort posts by time desc (newer ones first).

/pages/index.vue

<template>
<div>
  <button @click="reNew" class="btn"> Force update </button>
  <div class="grid grid-cols-4 gap-5">
    <div v-for="s in stories" :key="story">
      <StoryCard :story="s"/>
    </div>
  </div> 
</div>
</template>


  <script>  
  definePageMeta({
    layout: "stories"
  })
export default {
  data () {
    return {
      err: '',
      stories: [],
      interval:null,
    }
  },
  methods: {
    async reNew() {
        await $fetch('https://hacker-news.firebaseio.com/v0/topstories.json?print=pretty')
          .then((response) => {
            let results = response.slice(0, 10)
            results.forEach(id => {
            $fetch('https://hacker-news.firebaseio.com/v0/item/'+ id +'.json?print=pretty')
                .then((response) => {
                    this.stories.push(response)
                })
                .catch(err=> {
                  this.err = err
                })
            })
            
          }) 
      }
  },
  mounted() {
    this.reNew()
  },
  created(){
    this.interval = setInterval(() =>{
      this.mounted()},5000)
  },
  destroyed(){
    clearInterval(this.interval)
  }
  
}
</script>

<style scoped>
  .router-link-exact-active{
    color:#12b488;
  }
</style>

You can look at my code in components/StoryCard.vue below:

<template>
    <div>
        <div class="card text-center">
            <h2><strong>Title: </strong>{{story.title}}</h2>  
            <p><strong>Score: </strong>{{story.score}}</p>  
            <p><strong>Author: </strong>{{story.by}}</p>  
            <p><strong>Date: </strong>{{ new Date(story.time*1000) }}</p>  
            <NuxtLink :to="`/${story.id}`">
            <p class="btn my-4">View details</p> </NuxtLink>
        </div>
    </div>
</template>


<script setup>
    const { story } = defineProps(['story']) 
</script>

<style scoped>
    .thumb {
        max-height: 120px;
        max-width: 70%;
        margin: 0 auto;
    }
</style>

How can I sort posts by time desc (newer ones first)?

How can I do that here using Javascript?

kissu
  • 40,416
  • 14
  • 65
  • 133
Azizxon Zufarov
  • 107
  • 1
  • 3
  • 8

1 Answers1

0

The API that you're using is indeed the official one (listed at the bottom of the official HN page).
Unfortunately, there is nothing integrated regarding any kind of sort via the API itself.

You will need to use the .sort method to run on each object's date or similar field.

If we take that given URL with all the current posts: https://hacker-news.firebaseio.com/v0/topstories.json?print=pretty
We can see that each one of them is ordered based on upvotes. Hence, the array that you're receiving is full of objects like that one.

Once you have your huge array (in your stories state), it's a matter of running .sort on the time field which is nothing more than a UNIX timestamp.


So given the following subset of data (as a super simplified example)

stories = [
  { name: "On the Gift of Longhand", time: 1670073398 },
  { name: "Mac OS 9", time: 1670259607 },
]

you can run the following to have them sorted by "freshest" first

stories.sort((a, b) => b.time - a.time)

gives the following

[
  {
    "name": "Mac OS 9",
    "time": 1670259607 // aka December 5th
  },
  {
    "name": "On the Gift of Longhand",
    "time": 1670073398 // aka December 3rd
  }
]

The rest of the work is a matter of properly organizing your data and looping on it in your Vue code.

It may be quite un-efficient because it's a huge array (could use a backend middleware server to help the performance). Of course, a native API thing would be the best but I think that it's made on purpose (and hence will never come live).


Update

This is how you would sort the sorties depending on their time, regarding the starting point of my previous answer.

watch(responseSubset, async (newV) => {
  const unsortedStories = await Promise.all(responseSubset.value.map(async (id) => await $fetch(`https://hacker-news.firebaseio.com/v0/item/${id}.json?print=pretty`)))
  stories.value = unsortedStories.sort((a, b) => b.time - a.time)
})
kissu
  • 40,416
  • 14
  • 65
  • 133
  • Where should I put it: stories.sort((a, b) => b.time - a.time)? After which line?) That's a huge problem for me. – Azizxon Zufarov Dec 06 '22 at 02:48
  • @AzizxonZufarov this was an example. Of course, you will need to adapt it to your use case. There are several things to fix in your code. First step would be to use the [`fetch()` lifecycle hook](https://stackoverflow.com/questions/74691178/nuxt-js-hackernews-api-update-posts-without-loading-page-every-minute#comment131829381_74691178), then use only the `async/await` syntax (rather than `.then`). Then it's a matter of using the usual array methods on your `stories` state (as told above). Be sure to proceed with good basics in vanilla JS and VueJS so that you can learn efficiently. – kissu Dec 06 '22 at 02:52