2017-02-06 6 views
4

У меня есть список комментариев. Эти комментарии имеют атрибут «vote» (пользователи могут проголосовать за комментарии), и они первоначально сортируются по голосам (по убыванию, onRender).Можно ли сортировать коллекцию только один раз, а затем сохранить этот порядок без изменений, несмотря на реактивность?

Сейчас, когда пользователи голосуют, порядок комментариев обновляется с учетом новых голосов.

Возможно ли каким-либо образом сохранить первоначальный порядок сортировки неповрежденным? Я хотел бы избежать путать пользователя с комментариями, которые автоматически меняют порядок, пока он/она находится на странице.

Есть ли хороший способ решить эту проблему? Я думал, возможно, одноразовый сорт при рендеринге страницы, или как-то сохранить заказ, а затем повторно использовать его всякий раз, когда коллекция будет обновлена.

+0

Это интересная проблема. допустим, вы выяснили, как это сделать, и теперь появляется новый комментарий. где он входит в список? – zim

+0

Я бы сделал вызов метода, чтобы вытащить начальную подборку, отсортированную так, как вы хотите. Тогда у меня также есть подписка, которая проверяет наличие обновлений в базе данных и уведомляет пользователя о том, как твиттер делает это «2 новых комментария», и этот элемент пользовательского интерфейса снова щелкнет метод метеор. – sdybskiy

+0

@zim Либо в самом конце списка, либо совсем нет.Если я думаю об этом, единственной причиной, по которой я должен поддерживать реактивность вообще, является то, что я хочу, чтобы новые голоса пользователя отражались на странице. Ему не нужно сразу видеть новые или отредактированные комментарии или другие новые голоса пользователей. Поэтому, возможно, легким решением для меня было бы «подделка», просто увеличив количество голосов на стороне клиента. Пользователь вряд ли заметит разницу. Но все же, ради знания, я все равно хотел бы знать, будет ли выполнимый сценарий (с новыми комментариями в конце списка) выполнимым. – Cos

ответ

4

Вы можете использовать функцию для сортировки запроса Minimongo. Так что-то вроде:

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); 
}); 

Это позволит сделать так, чтобы комментарии сортировались по первоначальным голосам. Если что-либо еще изменится (например, пользователь отредактирует комментарии), это будет реактивно распространяться, если будет сделан новый комментарий, он будет реактивно добавлен. Но если голоса изменятся, порядок не изменится (но количество голосов, которое может быть оказано, будет по-прежнему обновляться).

+0

Звучит прекрасно! Я попробую позже и дам вам знать. Благодаря! – Cos

+0

Одна проблема: как мне сделать эту работу для любого количества комментариев? – Cos

+0

Что вы подразумеваете под этим? Это работает для любого количества комментариев. – Mitar

1

, так как вы не заботитесь о новых комментариях, только новые голоса, я бы сделал начальное население с помощью Meteor.call(), отсортированного по вашему желанию, как упоминалось @sdybskiy. то я бы установил подписку на эти комментарии, чтобы получить подсчет голосов.

в onCreated() вашего шаблона, вы можете настроить подписку, как это:

let voteCursor = Votes.find({commentIds: comments}); 
    voteCursor.observe({ 
     added: function(newDocument, oldDocument) { 
      // the published vote would have a commentId, so here you 
      // would go to your client store for the comments, find the 
      // comment, and increment the count 
     }, 
     removed: function(oldDocument) { 
      // same idea here, but process a vote being removed 
     } 
    }); 

уведомление я передаю в ид всех замечаний, возвращенных из метода, так что публиковать будет публиковать голоса только для этих комментариев.

+0

О, возможно, я не сделал это немного ясно: «Голоса» - это не их собственная коллекция, а простое поле чисел, которое является частью коллекции «Комментарии». – Cos

+0

@Cos, ага, никогда не думай! похоже, ответ Мишеля Флойда - это тот, который вы хотите. – zim

1

Вы можете сделать non-reactive find с reactive: false вариант, экс:

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

Если вы хотите добавить новые комментарии после первоначального списка, то я бы вынести два списка комментариев, один за другим. Сначала визуализируйте отсортированный список существующих комментариев, а затем порекомендуйте список комментариев, созданных после момента первоначальной рендеринга в порядке создания. Второй список изначально будет пустым и не будет отображаться вообще, но в конечном итоге новые комментарии появятся там с их собственным подсчетом голосов.

Теперь, поскольку курсор выше - это нереактивный, как мы собираемся подсчитывать количество голосов для обновления, не изменяя порядок? Ответ: (в случае с Blaze) используйте реактивный помощник!

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

Это на самом деле удивительно дешево с точки зрения производительности.

+0

Если я сделаю это нереактивным, новые голоса пользователя не будут видны на странице. Как я уже упоминал в комментарии выше, это может быть одним из решений, если я просто увеличиваю отображаемый подсчет голосов на стороне клиента. Но ради вопроса, могу ли я сделать так, чтобы комментарии были по-прежнему реактивными (за исключением порядка сортировки и даже при необходимости игнорируя новые комментарии)? – Cos

+0

Вы можете использовать реактивный * хелпер * для отображения количества голосов. См. Обновленный ответ. –

+0

Отличная идея, спасибо! – Cos

 Смежные вопросы

  • Нет связанных вопросов^_^