我的错误日志 - 在AngularJS中跨控制器共享其方法

时间:2013-08-01 09:31:53

标签: javascript angularjs controllers broadcasting

这个问题大约有一半是实际的,一半是概念性的。我看过对类似问题的回答,但我对AngularJS很新,我只是不确定最好的方式(我看到了一些不同的意见)来做到这一点(对我来说,无论如何),或者真的,我会写的实际代码,这就是为什么我用我自己的应用程序的细节问这个问题。

我知道这里有很多类似标题的问题,但我建议你继续阅读。

简而言之,我有一堆控制器,因为我有很多模型,我将它们整合到一个页面中。当前端向我的任何后端控制器发送请求(即用户操作)时,前端将得到如下响应:

{“success”:false,“errors”:[{“text”:“这是从PHP控制器发送的错误。”,“type”:“critical”}]}

但是,我想使用AngularJS为我的错误日志创建模型和视图(它只需要在客户端生存)。换句话说,应用程序中的每个其他控制器都需要访问错误日志控制器才能将事件添加到错误日志中。

我想我知道一些选项,比如创建共享服务/工厂和广播到rootscope。我也想知道是否有意义让所有其他控制器成为控制器的一个孩子,处理错误,警报等,虽然本能地,这对我来说是错误的。

最好的方法是什么(请记住,处理错误的同一个控制器也可以处理警报和其他全局类型的内务处理等事情),并且有人会帮我解决实际的代码问题在这个模型中,我嘲笑行为会是什么样子?

这是JSFiddle:http://jsfiddle.net/Ww8sS/2/

这是代码。这里可能有很多东西不是最好的办法,但就目前而言,我只关心我所描述的问题。

JS:

var userInterfaceApp = angular.module('user-interface', ['userInterfaceFilters']);

userInterfaceApp.controller('AnotherController', ['$scope', '$http', function($scope, $http) {

    $scope.doSomething = function() {
        $http({method: "JSONP", url: "http://uatu.net/test.php?action=do_something&callback=JSON_CALLBACK"}).
        success(function(data) {
            if(!data.success) {
                alert("How do I get the errors in data.errors to my error log?");
            }
        })
        .error(function(data, status, headers, config) {
            alert("Failure");
        // called asynchronously if an error occurs
        // or server returns response with an error status.
        });
    }
}]);

userInterfaceApp.controller('ConsoleEventController', ['$scope', function($scope) {
    $scope.errorLog = [];
    $scope.errorSortOrder = "-timestamp";

    $scope.addToErrorLog = function(errorArray) {
        for (var i = 0; i < errorArray.length; i++) {
            $scope.errorLog.push({"text" : errorArray[i].text, "type" : errorArray[i].type, "timestamp" : new Date()});
        }
    }

    //Not a real method--just here for demonstration
    $scope.createErrorMessage = function() {
        $scope.addToErrorLog([{"text" : "This is a sample error.", "type" : "critical"}]);
    }
}]);

var userInterfaceFilters = angular.module("userInterfaceFilters", []);

userInterfaceFilters.filter("logTimestamp", function() {
    return function(logDate) {
        var hours = logDate.getHours();
        var minutes = (logDate.getMinutes() < 10) ? "0" + logDate.getMinutes() : logDate.getMinutes();
        var seconds = (logDate.getSeconds() < 10) ? "0" + logDate.getSeconds() : logDate.getSeconds();
        return hours + ':' + minutes + ":" + seconds;
    };
});

我不得不使用JSONP使其在JSFiddle上运行。我不会在我的实际程序中这样做,因为它将全部在我的服务器上。

HTML:

<div ng-app="user-interface">
    <div ng-controller="AnotherController">
    <input type="button" value="Do Something" ng-click="doSomething()">    
    </div>

    <div ng-controller="ConsoleEventController">
        <p><input type="button" value="Create Error Message" ng-click="createErrorMessage()"></p>
        <h1>Error Log</h1>
        <ul id="error-log">
            <li ng-repeat="error in errorLog | orderBy:errorSortOrder" class="error-{{error.type}}">&lt;{{error.timestamp|logTimestamp}}&gt; {{error.text}}</li>
        </ul>
    </div>
</div>

2 个答案:

答案 0 :(得分:2)

听起来你已经知道最好的方法是走工厂/服务路线。但是不需要broadcast - 它们只是创建一个可以在必要时注入的单个实例。

以下是您可以采取行动的简单示例:http://jsfiddle.net/Ww8sS/3/

答案 1 :(得分:1)

对于我来说,使用消息传递范例(广播)更有意义,而不是使用工厂创建变量,在绑定到控制器的范围之后,因为它确实控制器和服务/工厂耦合在一起,所以你永远不会由于您的控制器将丢失与服务/工厂变量的链接,因此更改服务/工厂的变量。

例如,如果您想在服务/工厂中创建一个清除日志数组的新方法,以便创建新数组而不是清空当前数组,那么该更改将不会反映在该控制器的范围内,因为scope的变量指向旧的一个日志的数组;看一下例子:http://jsfiddle.net/Ww8sS/6/

var userInterfaceApp = angular.module('user-interface', ['userInterfaceFilters']);

userInterfaceApp.factory('errorLogs', function () {
    return {
        logs: [],
        addToErrorLog: function (errorArray) {
            for (var i = 0; i < errorArray.length; i++) {
                this.logs.push({"text": errorArray[i].text, "type": errorArray[i].type, "timestamp": new Date()});
            }
        },
        clearLogs: function () {
            this.logs = [];
        }
    }
});

userInterfaceApp.controller('AnotherController',
    ['$scope', '$http', 'errorLogs', function ($scope, $http, errorLogs) {

        $scope.doSomething = function () {
            $http({method: "JSONP", url: "http://uatu.net/test.php?action=do_something&callback=JSON_CALLBACK"}).
                success(function (data) {
                    if (!data.success) {
                        errorLogs.addToErrorLog(data.errors);
                    }
                })
                .error(function (data, status, headers, config) {
                    alert("Failure");
                    // called asynchronously if an error occurs
                    // or server returns response with an error status.
                });
        }
    }]);

userInterfaceApp.controller('ConsoleEventController',
    ['$scope', 'errorLogs', function ($scope, errorLogs) {
        $scope.errorLog = errorLogs.logs;
        $scope.errorSortOrder = "-timestamp";

        //Not a real method--just here for demonstration
        $scope.createErrorMessage = function () {
            errorLogs.addToErrorLog([
                {"text": "This is a sample error.", "type": "critical"}
            ]);
        }

        $scope.clearLogs = function () {
            errorLogs.clearLogs();
        };

    }]);

var userInterfaceFilters = angular.module("userInterfaceFilters", []);

userInterfaceFilters.filter("logTimestamp", function () {
    return function (logDate) {
        var hours = logDate.getHours();
        var minutes = (logDate.getMinutes() < 10) ? "0" + logDate.getMinutes() : logDate.getMinutes();
        var seconds = (logDate.getSeconds() < 10) ? "0" + logDate.getSeconds() : logDate.getSeconds();
        return hours + ':' + minutes + ":" + seconds;
    };
});

如果您使用消息传递范例,它会将控制器与服务解耦,而且服务是独立的,任何控制器都可以监听其事件; http://jsfiddle.net/Ww8sS/5/

    var userInterfaceApp = angular.module('user-interface', ['userInterfaceServices', 'userInterfaceFilters']);

    userInterfaceApp.controller('AnotherController', ['$scope', '$http', 'logger', function($scope, $http, logger) {

        $scope.doSomething = function() {
            $http({method: "JSONP", url: "http://uatu.net/test.php?action=do_something&callback=JSON_CALLBACK"}).
            success(function(data) {
                if(!data.success) {
                    logger.addToErrorLog(data.errors);
                    //alert("How do I get the errors in data.errors to my error log?");
                }
            })
            .error(function(data, status, headers, config) {
                alert("Failure");
            // called asynchronously if an error occurs
            // or server returns response with an error status.
            });

        }

         $scope.clearLog = function() {
          logger.clearLog();      
        }
    }]);

    userInterfaceApp.controller('ConsoleEventController', ['$scope', function($scope) {
        $scope.errorSortOrder = "-timestamp";
        $scope.errorLog;

        $scope.$on('logger.newErrors', function (evt, errArray) {  
             $scope.errorLog = errArray;
            });

        $scope.$on('logger.clearLog', function (evt) {  
             $scope.errorLog = [];
            });


        //Not a real method--just here for demonstration
        $scope.createErrorMessage = function() {
           // $scope.addToErrorLog([{"text" : "This is a sample error.", "type" : "critical"}]);
        }
    }]);

var userInterfaceFilters = angular.module("userInterfaceFilters", []);

userInterfaceFilters.filter("logTimestamp", function() {
    return function(logDate) {
        var hours = logDate.getHours();
        var minutes = (logDate.getMinutes() < 10) ? "0" + logDate.getMinutes() : logDate.getMinutes();
        var seconds = (logDate.getSeconds() < 10) ? "0" + logDate.getSeconds() : logDate.getSeconds();
        return hours + ':' + minutes + ":" + seconds;
    };
});


var userInterfaceServices = angular.module('userInterfaceServices', []);

userInterfaceServices.service('logger', ['$rootScope', function ($rootScope) {

        var errorLog = [];

        this.addToErrorLog = function(errorArray) {
            for (var i = 0; i < errorArray.length; i++) {
                errorLog.push({"text" : errorArray[i].text, "type" : errorArray[i].type, "timestamp" : new Date()});
            }

            $rootScope.$broadcast('logger.newErrors', errorLog);
        };

    this.clearLog = function () {
      errorLog = [];
        $rootScope.$broadcast('logger.clearLog', '');
    };
}]);

无论如何,这两种解决方案都有一些优点和缺点。