AngularJS 将部分 Controller 移至 Service

AngularJS move part of Controller to Service

考虑以下代码。

HTML:

<!doctype html>
<html ng-app="todoApp">
    <head>
        <meta charset="utf-8">
        <meta http-equiv="X-UA-Compatible" content="IE=edge">
        <meta name="viewport" content="width=device-width, initial-scale=1">

        <link href="/css/bootstrap.min.css" rel="stylesheet">
        <link href="/css/overlay-control.css" rel="stylesheet">
        <link href="/css/list-control.css" rel="stylesheet">

        <script src="http://code.jquery.com/jquery-1.10.2.js"></script>
        <script src="http://code.jquery.com/ui/1.11.2/jquery-ui.js"></script>
        <script src="http://maxcdn.bootstrapcdn.com/bootstrap/3.2.0/js/bootstrap.min.js"></script>
        <script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.4.8/angular.min.js"></script>
        <script src="https://ajax.googleapis.com/ajax/libs/jquery/1.11.3/jquery.min.js"></script>
        <!--<script src="/js/Services/UserService.js"></script>-->
        <script src="/js/Controllers/MainController.js"></script>
        <!--<script src="/js/Controllers/UserController.js"></script>-->
        <script src="/js/bootstrap.min.js"></script>
    </head>
    <body ng-controller="MainController as myControl">
        <div id="overlaycover" ng-click="myControl.showUpd(0)"></div>

        <div id="overlaybox">
            <div class="col-md-12">
            <h4>Update:</h4>
            <form ng-submit="myControl.updTodo()">
                <div class="form-group">
                    <label for="updContent">Note:</label>
                    <textarea rows="5" cols="30" class="form-control" id="updContent" name="updContent" ng-model="noteupd.content"></textarea>
                </div>
                <div class="form-group">
                    <label for="updDeadline">Deadline (format YYYY-MM-DD HH:MM:SS):</label>
                    <input type="text" class="form-control" id="updDeadline" name="updDeadline" ng-model="noteupd.deadline" />
                </div>
                <div class="checkbox">
                    <label>
                        <input type="checkbox" id="updCompleted" name="updCompleted" ng-model="noteupd.completed" /> - Completed
                    </label>
                </div>
                <div class="form-group">
                    <input type="hidden" id="updID" ng-model="noteupd.id" /><br/>
                    <button type="submit" class="btn btn-info">Update</button>
                </div>
            </form>
            Click utside the square to close.
            </div>
        </div>

        <div class="container">
            <div class="col-xs-12 col-sm-12 col-md-12 col-lg-12" id="listDiv">
                <h1>Todo-list:</h1>
                <p>
                    <img src="/images/legend-normal.png"> - Unfinished&emsp;
                    <img src="/images/legend-completed.png"> - Finished&emsp;
                    <img src="/images/legend-late.png"> - Late  
                </p>
                <table class="table" id="list-table">
                    <tr>
                        <th>Note:</th>
                        <th>Author:</th>
                        <th>Project:</th>
                        <th>Created:</th>
                        <th>Deadline:</th>
                        <th colspan="2">Modify:</th>
                    </tr>
                    <tr ng-repeat="todo in myControl.todos" ng-class="rowClass(todo.completed, todo.deadline)">
                        <td> {{ todo.content }} </td>
                        <td> {{ todo.user }} </td>
                        <td> {{ todo.project }} </td>
                        <td> {{ todo.created }} </td>
                        <td> {{ todo.deadline }} </td>
                        <td><button type="button" class="btn btn-info" ng-click="myControl.showUpd(todo.id)">Update</button></td>
                        <td><button type="button" class="btn btn-danger" ng-click="myControl.delTodo(todo.id)">Delete</button></td>
                    </tr>
                </table>
            </div>
            <div class="col-xs-12 col-sm-12 col-md-12 col-lg-12" id="formDiv">
                <h3>Add new note:</h3>
                <form ng-submit="myControl.addTodo()">
                    <div class="form-group">
                        <label for="newUser">User:</label>
                        <select ng-model="noteadd.user" class="form-control" id="newUser" name="newUser">
                            <option ng-repeat="user in myControl.users" value="{{ user.id }}">{{ user.name }}</option>
                        </select><br/>
                    </div>
                    <div class="form-group">
                        <label for="newProject">Project:</label>
                        <select ng-model="noteadd.project" class="form-control" id="newProject" name="newProject">
                            <option ng-repeat="project in myControl.projects" value="{{ project.id }}">{{ project.name }}</option>
                        </select><br/>
                    </div>
                    <div class="form-group">
                        <label for="newContent">Note:</label>
                        <textarea rows="5" cols="30" ng-model="noteadd.content" class="form-control" id="newContent" name="newContent"></textarea><br/>
                    </div>
                    <div class="form-group">
                        <label for="newDeadline">Deadline (format YYYY-MM-DD HH:MM:SS):</label>
                        <input type="text" ng-model="noteadd.deadline" class="form-control" id="newDeadline" name="newDeadline" /><br/>
                    </div>
                    <div class="form-group">
                        <button type="submit" class="btn btn-info">Add</button>
                    </div>
                </form>
            </div>
        </div>
    </body>
</html>

AngularJS 控制器:

angular.module('todoApp', []).controller('MainController', function($scope, $http) {
    var thisApp = this;
    $scope.noteadd = {};
    var noteadd = $scope.noteadd;
    $scope.noteupd = {};
    var noteupd = $scope.noteupd;

    // Get all notes:
    $http({method : 'GET', url : 'http://localhost:8000/notes'})
        .then (function(response) {
            thisApp.todos = response.data;
        }, function() {
            alert("Error getting todo notes");
        });

    // Get all users:
    $http({method : 'GET',url : 'http://localhost:8000/users'})
        .then(function(response) {
            thisApp.users = response.data;
        }, function() {
            alert("Error getting users");
        });


    // Get all projects
    $http({method : 'GET', url : 'http://localhost:8000/projects'})
        .then(function(response) {
            thisApp.projects = response.data;
        }, function() {
            alert("Error getting projects");
        });

    // Add note to database
    thisApp.addTodo = function(noteadd)
    {
        $http({
            method : 'PUT', 
            url : 'http://localhost:8000/notes',
            data : $.param($scope.noteadd),
            headers : {'Content-Type': 'application/x-www-form-urlencoded'}
        }).then(function(response) {
            location.reload();
        }, function() {
            alert("Couldn't add note. Please try again!");
        });
    };

    // Hide note by setting removed to 1
    thisApp.delTodo = function(noteID)
    {
        var r = confirm("Are you sure?");

        if (r == true) {
            var noteObj = JSON.parse('{"id":' + noteID + '}'); // JSON for req
            $http({
                method : 'DELETE', 
                url : 'http://localhost:8000/notes',
                data : $.param(noteObj),
                headers : {'Content-Type': 'application/x-www-form-urlencoded'}
            }).then(function(response) {
                location.reload();
            }, function() {
                alert("Couldn't delete note. Please try again!");
            });
        }
    };

    // Show overlay with form for updating a note
    thisApp.showUpd = function(noteID)
    {
        var overlaycover = document.getElementById("overlaycover");
        var overlaybox = document.getElementById("overlaybox");
        overlaycover.style.opacity = .65;

        if(overlaycover.style.display == "block" || noteID == 0){ // For toggling overlay
            overlaycover.style.display = "none"; // Hide div overlaycover
            overlaybox.style.display = "none"; // Hide div overlaybox
        } else {
            $http({method : 'GET', url : 'http://localhost:8000/notes/' + noteID})
                .then (function(response) {
                    noteupd.content = response.data.content; // Update fields in form
                    noteupd.deadline = response.data.deadline;
                    noteupd.id = response.data.id;

                    if (response.data.completed == 1) {
                        noteupd.completed = true;
                    } else {
                        noteupd.completed = false;
                    }

                    overlaycover.style.display = "block"; // Show div overlaycover
                    overlaybox.style.display = "block"; // Show div overlaybox
                }, function() {
                    alert("Error getting todo note");
                });
        }
    }

    // Update a note
    thisApp.updTodo = function(noteupd)
    {
        $http({
            method : 'POST', 
            url : 'http://localhost:8000/notes',
            data : $.param($scope.noteupd),
            headers : {'Content-Type': 'application/x-www-form-urlencoded'}
        }).then(function(response) {
            location.reload();
        }, function() {
            alert("Couldn't add note. Please try again!");
        });
    }

    // Check if deadline passed for each note in list
    $scope.rowClass = function(completed, deadline)
    {
        var nowTime = Math.floor(Date.now()/1000);
        var deadTime = new Date(deadline);
        var deadUTC = Math.floor(deadTime/1000);

        if (completed == 1) {
            return "success"; // Note is completed
        } else if (deadUTC < nowTime) {
            return "danger"; // Note is not completed, deadline passed
        } else {
            return "active"; // Note is not completed, still time left
        }
    }
});

我想做的是将所有 $http 调用移动到一个服务,而不是像现在这样将它们放在控制器中。我已经在互联网上进行了搜索,但我并不真正理解我在那里找到的解决方案。

其次,在几个函数中,如您所见,我使用了location.reload();。我想改用 ng-bind,但作为 sam,我不明白它是如何工作的。

有人可以解释一下我应该如何做这两件事吗?

好的,让我们创建一个 Users 工厂并将所有用户 api related 内容放入其中:

'use strict';

angular
    .module('todoApp')
    .factory('Users', factory);

    function factory($http) {
        var service = {
            get: get,
            //edit: edit ...
        };

        return service;

        function get() {
            return $http({method : 'GET',url : 'http://localhost:8000/users'})
            .then(function(response) {
                return response.data;
            });

        }

        //function edit(user) {
        //    return $http({method : 'PUT...
        //}

    }

接下来你要做的就是在你想调用它的地方注入那个工厂。

所以在你的控制器中你基本上必须这样做:

angular.module('todoApp', [])
    .controller('MainController', function($scope, Users) {

    //.....
    function getUsers() {
        Users.get().then(function(data){
            thisApp.users = response.data;
        }, function() {
            alert("Error getting users");
        });
    }      

    getUsers();
    //...

通过为笔记和项目创建适当的服务来重复相同的操作。

为了不让主 app.js 膨胀,将此服务移动到单独的文件,users.service.js 等。
我还建议您也将控制器移动到单独的文件中。

请注意:

这是一个模块创建

angular.module('todoApp', [])

您创建一个模块一次。

附加一个 service/factory/controller/anything,当你在那个单独的文件中时,你使用这个模块:

angular.module('todoApp').anything

其次,我假设您使用 location.reload 使用新数据更新视图。

假设您 edit/delete 是一个用户。不要重新加载页面,而是在 put/delete/create 用户的 then() 中调用 getUsers()

希望对您有所帮助!

PS:John Papas的这篇风格指南对我很有帮助,建议你读一读!

我已经使用过服务工厂解决方案来解决此类问题。

angular.module('data-service').factory('dataService', ['$http',function ($http) {
  var url = 'http://localhost:8000/';
  return {
    getData: function(type) {
      return $http({method : 'GET', url : url + type});
    },
    allData: function() {
      return $q.all({
        notes: this.getData('notes'),
        users: this.getData('users'),
        projects: this.getData('projects')
      });
    }
  }
}]);

用法:

dataService.getData('notes').then(function (data) { ... });

你也可以使用 angular promise $q.

dataService.allData().then(function(data) { /* data.notes, data.users, data.projects */ }