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.toJsonangular.fromJson 将所有日期对象转换为字符串。加载远程数据时,它使用自定义函数 convertDateStringsToDates() 将对象中的任何日期字符串转换为远程更新时的日期对象。