Building "Somebody is typing ..." using redis-oplog

Hi,

One of our clients requested a “somebody is typing” feature. Here is roughly how we implemented it using redis-oplog by @diaconutheodor.

First, please read the documentation at the repo of redis-oplog: https://github.com/cult-of-coders/redis-oplog

Start with an ordinary subscription

In our app, we have a collection called Questions. We list questions, and want each question to indicate if somebody is typing an answer to it. We receive documents from the Questions collection by using any publication that simply returns Questions.find(). Like this:

Meteor.publish('questions.all', function () {
  return Questions.find();
});

You can use Meteor.publishComposite or Meteor.publishWithRedis instead, if you want. In your template, you need to subscribe to this publication, but I’m going to assume you know how already.

Set typing status using keydown events and meteor methods

In our Template.createComment.events({}) we have an event handler that listens to keydown and keyup events on the/any textarea field.

Template.createComment.events({
  'keydown textarea': _.debounce(
    function (event, template) {
      Meteor.call('questions.isTyping', template.data.doc._id);
    },
    200
  ),
  'keyup textarea': _.debounce(
    function (event, template) {
      Meteor.call('questions.isNotTyping', template.data.doc._id);
    },
    1000
  ),
});

_.debounce is from the underscore library, and makes sure we don’t call the method too often.

Our meteor methods look like so:

import { SyntheticMutator } from 'meteor/cultofcoders:redis-oplog';

Meteor.methods({
  'questions.isTyping': function (questionId) {
    check(questionId, String);

    SyntheticMutator.update('questions', questionId, {
      $set: {
        somebodyIsTyping: true,
      },
    });
  },
  'questions.isNotTyping': function (questionId) {
    check(questionId, String);
    Meteor.setTimeout(
      function () {
        SyntheticMutator.update('questions', questionId, {
          $set: {
            somebodyIsTyping: false,
          },
        });
      },
      1000
    );
  },
});

The hero here is SyntheticMutator.update, which will only hit redis and not my server/db. It will set a “fake” property on my question documents, which I can use just like any other property and is reactive. In your blaze template, you can do something like:

{{#each questions}}
  {{#if somebodyIsTyping}}
    Somebody is typing.
  {{/if}}
{{/each}}

That’s it

There really isn’t much more to it. But, the potential is endless. Please make sure you read the documentation. I’m planning on writing a presence counter using redis-oplog soon, but feel free to beat me to it.

Thanks @diaconutheodor!!

I really appreciate you taking time and talking to me over Skype when I was first trying to figure this out. You are truly one of the heroes of Meteor. Hopefully I’ll have sometime soon to write about how redis-oplog solves our scaling issues, and I’m reading up on grapher!

9 Likes

If someone writes an article about how to build something like /r/place with redis-oplog, I think that would be huge.

4 Likes

@nadeemjq told you it was that easy!

4 Likes