2

Firebase is known for its real-time data update, so this is a weird one for me.

I am using Firebase 3 (New firebase console app. Want to add authentication later) and AngularFire 2. I started the app using Ionic's tab template so the app.js' router config should be the same.

Click here to see a (90 second) video demo of the issue

I have my ionic app served to the browser using 'ionic serve --lab' so I can see iOS and Android view.

  • When I try to toggle data in one view (say iOS), the changes are instatly shown in firebase DB, but does now show immediately in the other view (Android) until I either toggle something, or change tabs in that view.

  • On the other hand, if I make a change in the firebase DB, then neither of the two views are updated until I either person an action or change tabs for each view.

Few other observations:

  • Sometimes on load, neither of the view has data loaded from firebase db until tabs are switched or 'Add Property' button is clicked for each view. (Least common) enter image description here
  • Sometimes, one view has the data loaded, while the other does not until tabs are switched or 'Add Property' button is clicked for that view. enter image description here enter image description here
  • I uploaded the app to ionic.io to try it on my phone using ionic view, and I got same results where DB would update, but the views would not until a change was triggered.

HTML (containing toggles):

<ion-view view-title="Dashboard">
  <ion-content class="padding">
    <button class="button button-block button-positive" ng-click="addProperty()">Add Test Property</button>
    <div class="list" ng-repeat="(key, property) in properties">
      <ion-toggle class="item item-divider" ng-model="property.status" ng-true-value="'on'"
        ng-false-value="'off'" ng-change="togglePower(property, key)"> {{ property.name }}
      </ion-toggle>
    </div>
  </ion-content>
</ion-view>

Index.html

<!-- ionic/angularjs js -->
<script src="lib/ionic/js/ionic.bundle.js"></script>

<!-- cordova script (this will be a 404 during development) -->
<script src="cordova.js"></script>

<!-- Firebase & AngularFire --> // I tried saving them and loading from locally
<script src="https://www.gstatic.com/firebasejs/3.2.0/firebase.js"></script>
<script src="https://cdn.firebase.com/libs/angularfire/2.0.1/angularfire.min.js"></script>

<script>
  // Initialize Firebase
  var config = {
    apiKey: "API_KEY",
    authDomain: "projectName.firebaseapp.com",
    databaseURL: "https://projectNamefirebaseio.com",
    storageBucket: "projectName.appspot.com"
  };
  firebase.initializeApp(config);
</script>

<!-- your app's js -->
<script src="js/app.js"></script>
<script src="js/controllers.js"></script>
<script src="js/services.js"></script>

Controller.js

controller('DashCtrl', function ($scope) {
    var propertiesRef = firebase.database().ref('properties');

    propertiesRef.on('value', function (data) {
      $scope.properties = data.val();
    }, function (errorObject) {
      console.log("Error getting the properties: " + errorObject.code);
    });

    var id = 0;
    $scope.addProperty = function () {
      propertiesRef.push({
        name: "Test " + id++,
        status: "on"
      }).then(function () {
        console.log("Property Added!");
      });
    };

    $scope.togglePower = function (device, key) {
      propertiesRef.child(key).update({
        "status": device.status
      });
    };
};

Let me know if any additional is needed. I am not able to understand what seems to be the issue.

Ali
  • 558
  • 7
  • 28

1 Answers1

3

As you can see, when you click the toggle in the android app all the toggles gets updated. This is because when you perform a click you trigger the digest cicle

You should call $scope.$apply() after updating your scope variable, or wrapping it in a timeout

controller('DashCtrl', function ($scope, $timeout) {
    var propertiesRef = firebase.database().ref('properties');

    propertiesRef.on('value', function (data) {
      $timeout(function() {
        $scope.properties = data.val();
      })
    }, function (errorObject) {
      console.log("Error getting the properties: " + errorObject.code);
    });
};
Community
  • 1
  • 1
Devid Farinelli
  • 7,514
  • 9
  • 42
  • 73
  • Thanks Devid. I think it is working. I will running a few more tests and accept your answer afterwards. Do you know why is that happening because with Firebase 2.4.2 and Angularfire 1.2, I did not have to do the timeout. Also, is it possible to replace timeout without a defer-promise or something? – Ali Jul 14 '16 at 11:20
  • I suggest you, to take a loot at this. The "problem" is caused by Angular's digest cycle. Sometimes you have to tell Angular to refresh the view, it always happened to me with Angular :) – Devid Farinelli Jul 14 '16 at 14:31