Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

When using AngularFire, the cursor jumps to end of field while typing

I setup a tiny sample app that edits one field. But when I type in that field the contents keep reverting back to a second ago. I'm looking for a fix to AngularFire that makes it just work, or a RTFM where I'm just not initializing it right. At this point bindTo() is not useable and I can't move forward on using AngularFire at all.

Here's the full sample (and you can open it at http://jsbin.com/wabafu/3):

<!DOCTYPE html>
<html ng-app="myapp">
  <head>
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.3.0-beta.14/angular.min.js"></script>
    <script src='https://cdn.firebase.com/js/client/1.0.19/firebase.js'></script>
    <script src='https://cdn.firebase.com/libs/angularfire/0.8.0/angularfire.min.js'></script>
    <script>
      var app = angular.module("myapp", ["firebase"]);
      function MyController($scope, $firebase) {
        var ref = new Firebase("https://stackoverflow25331760.firebaseIO.com/"),
            syncObject = $firebase(ref).$asObject();
        syncObject.$bindTo($scope, "data");
      }
    </script>
  </head>
  <body ng-controller="MyController">
    <h3>
      <input type="checkbox" ng-model="EditMode"> Enable Editing
    </h3>
    <div ng-if="EditMode">
      <input type="text" ng-model="data.SyncValue" style="width:100%">
    </div>
    <div ng-if="!EditMode">
      {{data.SyncValue}}
    </div>
  </body>
</html>

It works smooth when only open in one browser, but when open in multiple, I can't type more than a word or two without the text contents reverting back to a few keystrokes ago and the cursor moving to the end of the field.

I imagine the events happening are:

  1. I type, the value gets updated in angularjs (GOOD)
  2. Angularfire sends the new value to firebase (GOOD)
  3. Firebase sends the value to other browsers (while I continue typing) (GOOD)
  4. Other browsers receive the new value and update their html (GOOD)
  5. Other browsers re-send the value back to firebase as if it was new info (REALLY BAD)
  6. Firebase receives this echoed outdated value and pushes it back to me (BAD)
  7. My browser gets this second-old value and since it's different than what's now in my text field, the contents of my fiedl gets reverted (BAD)

Am I imagining the process wrong? What should I do to stop step 5?

P.S. While testing, I found I can work around #7 by typing only a few characters quickly and then waiting 2 seconds, repeat. That way the value doesn't change while the sync is echoing and my cursor won't jump.

P.P.S. To try to narrow it down, I've made a checkbox that controls if the data is displayed in a field, or just a read-only div. Even if the second browser is only displaying the data, this echo/reverting behavior still exists in the first browser. The only way for data to store in firebase correctly is if I only have one browser using it at a time.

like image 677
efreed Avatar asked Aug 15 '14 18:08

efreed


1 Answers

I've had good success by adding a debounce onto the input.

<input type="text" ng-model="data.field" 
    ng-model-options="{ updateOn: 'default blur', debounce: {'default': 500, 'blur': 0} }" />

Also, $bindTo isn't strictly necessary here. It's not particularly hard to manually save the data and skip the $bindTo.

$scope.data = $firebase(new Firebase(...)).$asObject();

<input type="text" ng-model="data.field" ng-blur="data.$save()" />
like image 194
Kato Avatar answered Nov 07 '22 17:11

Kato