Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Is it possible to sort a collection only once and then keep that order intact despite reactivity?

I have a list of Comments. These comments have an attribute called "vote" (users can vote comments) and they are initially sorted by votes (descending, onRender).

Right now, when users vote, the order of the comments is reactively updated to reflect the new votes.

Is it possible to somehow keep the initial sorting order intact? I would like to avoid confusing the user with comments automatically swapping order while she/he is on the page.

Is there any good way to solve this? I was thinking perhaps of a one-time sort when rendering the page, or somehow saving the order and then reapplying it whenever the collection is reactively refreshed.

like image 608
Cos Avatar asked Mar 10 '23 22:03

Cos


2 Answers

You could use a function to sort your Minimongo query. So something like:

const initialVotes = new Map();
Comments.find({}, {sort: (a, b) => {
  if (!initialVotes.has(a._id)) initialVotes.set(a._id, a.votes);
  if (!initialVotes.has(b._id)) initialVotes.set(b._id, b.votes);

  return initialVotes.get(b._id) - initialVotes.get(a._id);
});

This will make it so that comments are sorted by initial votes. If anything else changes (like user edits the comments), that will reactively propagate, if a new comment is made, it will reactively be added. But if votes change, order will not change (but the vote number maybe rendered will still update).

like image 182
Mitar Avatar answered Apr 30 '23 04:04

Mitar


You can do a non-reactive find with the reactive: false option, ex:

Comments.find({},{sort: {vote: -1}, reactive: false});

If you want to append new comments after the original list then I would render two lists of comments, one right after the other. First render the sorted list of existing comments then reactively render the list of comments that were created after the time of initial rendering in creation order. The second list will initially be empty and will not render at all but eventually new comments will appear there with their own vote counts.

Now, since the cursor above is non-reactive, how do we go about getting the vote counts to update reactively without changing the order? Answer: (in the case of Blaze) use a reactive helper!

Template.myTemplate.helpers({
  currentVote(){
    return Comments.findOne(this._id).vote;
  }
});

This is actually surprisingly cheap from a performance pov.

like image 29
Michel Floyd Avatar answered Apr 30 '23 04:04

Michel Floyd