AngularJS 连接或断开连接到 Firebase 时更新服务值

AngularJS update Service values when connected or disconnected to firebase

我希望在连接或断开连接到 Firebase 服务器时更改图标颜色。我做到了这一点:

HTML

<button class="button button-icon ion-cloud" ng-style="dbConnectedStyle"></button>

控制器

firebaseRef.$loaded().then( function() {
  $scope.dbConnectedStyle = {'color': dbConnectStatus.color};
}

服务

.service('dbConnectStatus', function(firebaseRef){
  var status = false;
  var color = 'transparent';
  var connectedRef = firebaseRef.child(".info/connected");
  connectedRef.on("value", function(snap) {
    status = snap.val();
    if (status) {
      color = 'lightgrey';
      console.log("Connected to DB (" + color + ")" );
    } else {
      color = 'transparent';
      console.log("Disonnected to DB (" + color + ")" );
    }
  });
  return {
    'boolean': status,
    'color': color
  }
})

第一次变色。但是当断开连接时它不会改变......似乎它不是双向绑定到服务。我该如何实现?


更新

尝试将服务作为对象进行引用,而不是按照优秀教程中的说明进行基元分配 A Tale of Frankenstein and Binding to Service Values in Angular.js

我把代码改成了下面的

HTML

<button class="button button-icon ion-cloud" 
        ng-style="dbConnectionStatus.connectionStyle">
        </button>

服务

.service('dbConnectStatus', function(firebaseRef, $rootScope){
  this.status = false;
  var styles = {
    'offlineStyle': {'color': 'red'},
    'onlineStyle': {'color': 'lightgrey'}
  };
  this.connectionStyle = styles.offlineStyle;

  firebaseRef.child(".info/connected")
    .on("value",
      function(snap) {
        this.status = snap.val();
        if (snap.val()) {
          console.log("Connected to DB.");
          this.connectionStyle = styles.onlineStyle;
          console.log(this.connectionStyle);
        } else {
          console.log("Disconnected to DB.");
          this.connectionStyle = styles.offlineStyle;
          console.log(this.connectionStyle);
        }
        console.log(this.status);
        $rootScope.$broadcast('dbConnection:changed');            
      }
    );

})

控制器

$scope.dbConnectionStatus = dbConnectStatus;
      $scope.$on('dbConnection:changed', function() {
        console.log("'on(...)' called. This is the $scope.dbConnectionStatus.connectionStyle:");
        $scope.dbConnectionStatus = dbConnectStatus;
        console.log($scope.dbConnectionStatus.connectionStyle);
        console.log("This is the dbConnectStatus.connectionStyle:");
        console.log(dbConnectStatus.connectionStyle);
      });
      $rootScope.$watch('dbConnectStatus', function (){
        $scope.dbConnectionStatus = dbConnectStatus;
      });
      //$rootScope.$apply();

然后我重新加载代码并收到此控制台消息

然后我关闭了连接

然后我打开连接

我很清楚服务 dbConnectionStatus 没有按照我预期的方式更新为全局变量。我假设在加载应用程序时调用一次服务,并且将范围变量分配给服务(对象)不是调用而是引用...

我做错了什么?

我在 jsFiddle 工作,使用 $emit$on 来处理服务内部的状态变化。主要问题是,当上网时 angular 绑定无法正常工作,所以我需要用 $scope.$apply().

强制执行 angular 循环

我开始编写您代码的第一个版本,但进行了一些重构。您可以在 jsFiddle 上找到完整代码,但服务和控制器如下所示:

服务

.service('dbConnectStatus', function($rootScope){
  var status = false;
  var color = 'red';
  var self = {      
        startWatchingConnectionStatus: function(){
        var connectedRef = firebase.database().ref().child(".info/connected");
        connectedRef.on("value", function(snap) {
            console.log(snap.val());
            status = snap.val();
            if (status) {
                color = 'blue';
                console.log("Connected to DB (" + color + ")" );
            } else {
                color = 'red';
              console.log("Disonnected to DB (" + color + ")" );
              }
            $rootScope.$emit('connectionStatus:change', {style: {'color': color}, status: status}});
        });
      },
      getStatus: function(){
        return status;
      },
      getColor: function(){
        return color;
      }
  };
  return self;
})

控制器

.controller('HomeCtrl', ['$scope', 'dbConnectStatus', '$rootScope',function($scope, dbConnectStatus, $rootScope) {

    dbConnectStatus.startWatchingConnectionStatus();

    $rootScope.$on('connectionStatus:change',  function currentCityChanged(event, value){
        $scope.color = value.style;
        //if changed to connected then force the $apply
        if(value.status === true){
            $scope.$apply();
        }
    });  
}]);

如果还有什么不清楚的地方,请告诉我。

受@adolfosrs 出色回答的启发,我发现以下解决方案适合我。

服务

.service('dbConnectStatus', function(firebaseRef, $rootScope){
  // Initial setup
  var styles = {
    'offlineStyle': {'color': 'red'},
    'onlineStyle': {'color': 'skyeblue'}
  };

  // Functions to switch status
  var offline = function () {
    this.boolean = false;
    this.style = styles.offlineStyle;
  }
  var online = function () {
    this.boolean = true;
    this.style = styles.onlineStyle;
  }

  var get_status = function(){
    return {
      boolean: this.boolean,
      style: this.style
    }
  }

  // Read the firebase info and update when changed
  firebaseRef.child(".info/connected")
    .on("value", function(snap) {
        if (snap.val()) {
          online();
        } else {
          offline();
        }
        $rootScope.$emit('dbConnection:changed', get_status() );
    });
})

控制器

// Hide it before the status is known.
$scope.dbConnectionStatus = {'color': 'transparent'}; 
// Getting and reading status changes
$rootScope.$on('dbConnection:changed', function(event, status) {
    $scope.dbConnectionStatus = status.style;
    $scope.$apply();
  });

您应该能够通过将颜色存储在服务中的对象中并从控制器中引用它来简单地实现此功能。例如

查看

<button class="button button-icon ion-cloud" ng-style="dbStatusService.style"></button>

控制器

$scope.dbStatusService = dbConnectStatus;

服务

.service('dbConnectStatus', function(firebaseRef){
    var status = false;
    var style = {color: 'transparent'};
    var connectedRef = firebaseRef.child(".info/connected");
    connectedRef.on("value", function(snap) {
        status = snap.val();
        if (status) {
            style.color = 'lightgrey';
        } else {
            style.color = 'transparent';
        }
    });
    return {
        'boolean': status,
        'style': style
    }
});