AngularJS 和 Firebase 的 3 向绑定日期格式
3-way bind date format with AngularJS and Firebase
在我所有的项目中,我 运行 都遇到了同样的问题,试图找出最好的方法是用我的视图和 Firebase 绑定时间戳(日期)。我目前正在使用 Angular-Material 中的 md-datepicker
指令,但不幸的是,该指令仅支持日期对象,并且由于 Firebase 不接受日期对象,因此该值将始终为空.
在几个项目中,我在 Firebase 中以毫秒为单位存储纪元时间戳。是否有可能在 Firebase 和 md-datepicker
?
中使用纪元时间戳进行适当的三向数据绑定
谢谢!
通过创建我自己的绑定函数并在保存时转换为 ISO 日期字符串并在获取时将其转换为日期对象来解决此问题。
它使用 $parse 计算给定范围内的表达式并更新该范围内的局部变量。这是服务:
angular.module('symApp').service('realtimeService', function($rootScope, $q, $log, $window, $state,
$firebaseObject, $parse) {
// Utilities
var regexIso8601 = /^([\+-]?\d{4}(?!\d{2}\b))((-?)((0[1-9]|1[0-2])(([12]\d|0[1-9]|3[01]))?|W([0-4]\d|5[0-2])(-?[1-7])?|(00[1-9]|0[1-9]\d|[12]\d{2}|3([0-5]\d|6[1-6])))([T\s]((([01]\d|2[0-3])((:?)[0-5]\d)?|24\:?00)([\.,]\d+(?!:))?)?([0-5]\d([\.,]\d+)?)?([zZ]|([\+-])([01]\d|2[0-3]):?([0-5]\d)?)?)?)?$/;
var convertDateStringsToDates = function (input) {
// Ignore things that aren't objects.
if (typeof input !== "object") return input;
for (var key in input) {
if (!input.hasOwnProperty(key)) continue;
var value = input[key];
var match;
// Check for string properties which look like dates.
if (typeof value === "string" && (match = value.match(regexIso8601))) {
var milliseconds = Date.parse(match[0]);
if (!isNaN(milliseconds)) {
input[key] = new Date(milliseconds);
}
} else if (typeof value === "object") {
// Recurse into object
convertDateStringsToDates(value);
}
}
};
this.bindVar = function(scope, remote_path, local_var_name) {
// This function binds a local variable in scope to a remote variable in firebase
// and handles any dates by converting them into iso formatted strings.
// Note: Arrays inside the object are not supported
// Parse the local variable name so we can interact with the scope variable
var parsed = $parse(local_var_name);
// Grab the reference to the realtime database
var ref = firebase.database().ref().child(remote_path);
// Create the firebase object and set watchers to bind the data
var remote = $firebaseObject(ref);
remote.$loaded().then(function() {
// Watch for changes and call $save on firebaseObject
// Have to do this when loaded otherwise we'll get a change from nothing to null and write null to realtime database...
// Local watcher
scope.$watch(local_var_name,
function(value) {
// This is called when the local variable changes
$log.debug(local_var_name, 'local value changed');
// Convert to JSON to change dates to strings
var local = angular.fromJson(angular.toJson(parsed(scope)));
// Check if local has changed with respect to remote (stops us from saving when we don't need to)
if(!angular.equals(remote.value, local)){
remote.value = local;
remote.$save();
$log.debug(local_var_name, 'saved to remote with value: ', remote.value);
}
},
true
);
// Remote watcher
scope.$watch(
function () {
return remote.value;
},
function(value) {
// If the firebase value has changed, then update the local value
$log.debug(local_var_name, 'remote value changed');
// Convert date strings from firebase into date objects before setting scope variable
var remote_with_date_objects = $.extend(true,{},remote.value);
convertDateStringsToDates(remote_with_date_objects);
if(!angular.equals(remote_with_date_objects,parsed(scope))){
parsed.assign(scope, remote_with_date_objects);
$log.debug(local_var_name, 'updated with remote value: ', remote_with_date_objects);
}
},
true
);
});
};
});
下面是如何在控制器中使用它来绑定范围变量:
realtimeService.bindVar($scope, 'datum/charter', 'charter');
我的 $scope.charter 对象有自己的对象和数组,一切似乎都正确同步。保存数据时,它使用 angular.toJson 和 angular.fromJson 将所有日期对象转换为字符串。加载远程数据时,它使用自定义函数 convertDateStringsToDates() 将对象中的任何日期字符串转换为远程更新时的日期对象。
在我所有的项目中,我 运行 都遇到了同样的问题,试图找出最好的方法是用我的视图和 Firebase 绑定时间戳(日期)。我目前正在使用 Angular-Material 中的 md-datepicker
指令,但不幸的是,该指令仅支持日期对象,并且由于 Firebase 不接受日期对象,因此该值将始终为空.
在几个项目中,我在 Firebase 中以毫秒为单位存储纪元时间戳。是否有可能在 Firebase 和 md-datepicker
?
谢谢!
通过创建我自己的绑定函数并在保存时转换为 ISO 日期字符串并在获取时将其转换为日期对象来解决此问题。
它使用 $parse 计算给定范围内的表达式并更新该范围内的局部变量。这是服务:
angular.module('symApp').service('realtimeService', function($rootScope, $q, $log, $window, $state,
$firebaseObject, $parse) {
// Utilities
var regexIso8601 = /^([\+-]?\d{4}(?!\d{2}\b))((-?)((0[1-9]|1[0-2])(([12]\d|0[1-9]|3[01]))?|W([0-4]\d|5[0-2])(-?[1-7])?|(00[1-9]|0[1-9]\d|[12]\d{2}|3([0-5]\d|6[1-6])))([T\s]((([01]\d|2[0-3])((:?)[0-5]\d)?|24\:?00)([\.,]\d+(?!:))?)?([0-5]\d([\.,]\d+)?)?([zZ]|([\+-])([01]\d|2[0-3]):?([0-5]\d)?)?)?)?$/;
var convertDateStringsToDates = function (input) {
// Ignore things that aren't objects.
if (typeof input !== "object") return input;
for (var key in input) {
if (!input.hasOwnProperty(key)) continue;
var value = input[key];
var match;
// Check for string properties which look like dates.
if (typeof value === "string" && (match = value.match(regexIso8601))) {
var milliseconds = Date.parse(match[0]);
if (!isNaN(milliseconds)) {
input[key] = new Date(milliseconds);
}
} else if (typeof value === "object") {
// Recurse into object
convertDateStringsToDates(value);
}
}
};
this.bindVar = function(scope, remote_path, local_var_name) {
// This function binds a local variable in scope to a remote variable in firebase
// and handles any dates by converting them into iso formatted strings.
// Note: Arrays inside the object are not supported
// Parse the local variable name so we can interact with the scope variable
var parsed = $parse(local_var_name);
// Grab the reference to the realtime database
var ref = firebase.database().ref().child(remote_path);
// Create the firebase object and set watchers to bind the data
var remote = $firebaseObject(ref);
remote.$loaded().then(function() {
// Watch for changes and call $save on firebaseObject
// Have to do this when loaded otherwise we'll get a change from nothing to null and write null to realtime database...
// Local watcher
scope.$watch(local_var_name,
function(value) {
// This is called when the local variable changes
$log.debug(local_var_name, 'local value changed');
// Convert to JSON to change dates to strings
var local = angular.fromJson(angular.toJson(parsed(scope)));
// Check if local has changed with respect to remote (stops us from saving when we don't need to)
if(!angular.equals(remote.value, local)){
remote.value = local;
remote.$save();
$log.debug(local_var_name, 'saved to remote with value: ', remote.value);
}
},
true
);
// Remote watcher
scope.$watch(
function () {
return remote.value;
},
function(value) {
// If the firebase value has changed, then update the local value
$log.debug(local_var_name, 'remote value changed');
// Convert date strings from firebase into date objects before setting scope variable
var remote_with_date_objects = $.extend(true,{},remote.value);
convertDateStringsToDates(remote_with_date_objects);
if(!angular.equals(remote_with_date_objects,parsed(scope))){
parsed.assign(scope, remote_with_date_objects);
$log.debug(local_var_name, 'updated with remote value: ', remote_with_date_objects);
}
},
true
);
});
};
});
下面是如何在控制器中使用它来绑定范围变量:
realtimeService.bindVar($scope, 'datum/charter', 'charter');
我的 $scope.charter 对象有自己的对象和数组,一切似乎都正确同步。保存数据时,它使用 angular.toJson 和 angular.fromJson 将所有日期对象转换为字符串。加载远程数据时,它使用自定义函数 convertDateStringsToDates() 将对象中的任何日期字符串转换为远程更新时的日期对象。