Обновление 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
}
});