2

I have a text area that I am synchronizing with GoInstant. here is what the code looks like:

var myRoom = platform.room('myRoom');
var myKey = myRoom('myKey');

// Listen to set events on the platform key and update a textarea
myKey.on('set', function(textAreaContent) {
  $('textarea').val(textAreaContent);
});

// When the textarea changes, set the platform key
$('textarea').on('change', function(){
  var textAreaContent = $(this).val();
  myKey.set(textAreaContent, function(err) {
    if (err) throw err;
  });
})

This creates an infinite loop, when updating one text field i.e. When changing the value of the textarea, this triggers a Platform key update, which in turn changes the value of the textarea infinitely ...

EDIT: Based on the top answer I came up with the following constructor:

function BounceProtection() {
  var remoteUpdate = false; // remote toggle
  this.local = function(cb) {
    if (remoteUpdate) return;
    cb();
  };
  this.remote = function(cb) {
    remoteUpdate = true;
    cb();
    remoteUpdate = false;
  };
}

This way, I can generate bounceProtection objects as needed to protect multiple keys even with the asynchronous nature of js.

var myKeyBP = new BounceProtection();
Pykler
  • 14,565
  • 9
  • 41
  • 50
  • 1
    How so? The `$textarea.val()` inside the `on("set")` listener does not trigger a `change` event… – Bergi Jul 17 '13 at 13:32
  • It does when the remote user's myKey.on even is fired, which then triggers a change event which then does a myKey.set to everyone remotely ... (loop) – Pykler Jul 17 '13 at 13:36
  • Then just remove that code for triggering `change` events on the textarea when `set` events on the `myKey` happen? – Bergi Jul 17 '13 at 13:49

3 Answers3

5

A quick method of preventing an infinite propagation loop:

// Infinite loop prevention
var bounceProtection = {
  remoteUpdate: false, // remote toggle
  local: function(cb) {
    if (this.remoteUpdate) return;
    cb();
  },
  remote: function(cb) {
    this.remoteUpdate = true;
    cb();
    this.remoteUpdate = false;
  }
};

var myRoom = platform.room('myRoom');
var myKey = myRoom.key('myKey');

myKey.on('set', function(textAreaContent) {
  bounceProtection.local(function() {
    $('textarea').val(textAreaContent);
  });
});

$('textarea').on('change', function(){
  var textAreaContent = $(this).val();
  bounceProtection.remote(function() {
    myKey.set(textAreaContent, function(err) {
      if (err) throw err;
    });
  });
});
Slukehart
  • 1,037
  • 5
  • 15
  • Slight modification to the bounceProtection ... a singleton will only work for one set/change pair. We need to create bounceProtection objectsfor each set/change pair we want to protect. Changed bounceProtection into an obj generator (factory/constructor/...) function ... see update above. – Pykler Aug 02 '13 at 16:10
1

Simply remove the listener before editing the textarea and then reapply it (I also cached your textarea for you so you don't search the DOM on every triggered event).

I also suggest you give the textarea an ID attribute as it appears you are working with one textarea but doing a tag search which is inefficient and easily broken by adding another textarea to the page.

var myRoom = platform.room('myRoom');
var myKey = myRoom('myKey');

var $textarea = $('textarea');

function setKey() {
  var textAreaContent = $(this).val();
  myKey.set(textAreaContent, function(err) {
    if (err) throw err;
  });
}

// Listen to set events on the platform key and update a textarea
myKey.on('set', function(textAreaContent) {
  $textarea.off('change', setKey); // Remove listener
  $textarea.val(textAreaContent);
  $textarea.on('change', setKey); // Reapply listener
});

// When the textarea changes, set the platform key
$textarea.on('change', setKey);
George Reith
  • 13,132
  • 18
  • 79
  • 148
  • This should work. The bounceProtection snippet in the other answer though is a more universal solution. – Pykler Jul 17 '13 at 13:39
0

Another possible way is to compare values first before setting the value. Arguably not generic enough in the case where events do not have comparable values, but in this case this solution would work.

myKey.on('set', function(textAreaContent) {
  var $textarea = $('textarea');
  if ($textarea.val() !== textAreaContent) { // compare values first
    $textarea.val(textAreaContent);
  }
});

// When the textarea changes, set the platform key
$('textarea').on('change', function(){
  var textAreaContent = $(this).val();
  myKey.set(textAreaContent, function(err) {
    if (err) throw err;
  });
})
Jonathan Lin
  • 19,922
  • 7
  • 69
  • 65