Обновление AngularJS Сервисные значения при подключении или отключении от 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
  }
})

Он меняет цвет в первый раз. Но при отключении его не меняется... похоже, что это не двусторонняя привязка к сервису. Как достичь этого?


UPDATE

Пытался сделать ссылку на Сервис как объект, а не выполнять назначения примитивов, как объяснено в хорошем учебнике Сказка о Франкенштейне и привязка к служебным значениям в 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 не обновляется как глобальная переменная так, как я ожидал. Я полагал, что служба вызывается один раз, когда приложение является нагрузкой, и что назначение переменной области для объекта (объекта) не является вызовом, а ссылкой...

Что я делаю неправильно?

Ответ 1

Я работал в jsFiddle с помощью $emit и $on для обработки изменений статуса внутри службы. Основная проблема заключается в том, что при переходе в сеть привязка angular не работала должным образом, поэтому мне нужно было заставить цикл angular с $scope.$apply().

Я начал работать над первой версией вашего кода, но сделал несколько рефакторингов. Вы можете найти полный код на 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();
        }
    });  
}]);

Сообщите мне, есть ли что-то еще непонятное.

Ответ 2

Вдохновленный отличным ответом @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();
  });

Ответ 3

Вы должны иметь возможность получить это, просто сохраняя цвет в объекте в службе и ссылаясь на него с контроллера. например.

Вид

<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
    }
});