Объединение ресурсов в AngularJS

У меня есть RESTful API, который предоставляет мне сотрудников и отделы. В моем приложении AngularJS мне нужно знать сотрудника и отделы, к которым он принадлежит. Для этого я определил два фабричных сервиса:

angular.module('myApp.services', [])
    .factory('Employee', function ($resource) {
        return $resource ('/api/employees/:id', { id: '@id' });
    })
    .factory('Department', function ($resource) {
        return $resource ('/api/departments/:id', { id: '@id' });
    })
;

В контроллере я вызываю:

$scope.employee = Employee.get({id: 'me'});

Далее я хочу позвонить:

$scope.departments = [];
angular.forEach($scope.employee.departmentIds, function (departmentId) {
    $scope.departments.push(Department.get({ id: departmentId }));
});

Но $scope.employee — объект обещания, поэтому $scope.employee.departmentIds будет известно только после завершения первого запроса.

Я мог бы решить это так:

Employee.get({id: 'me'}).$promise.then(function (employee) {
    $scope.employee = employee;
    $scope.departments = [];
    angular.forEach(employee.departmentIds, function (departmentId) {
        $scope.departments.push(Department.get({ id: departmentId }));
    });
});

Проблема в том, что мне нужна эта информация в нескольких контроллерах, и я не хочу повторять этот код в каждом контроллере. Итак, мой вопрос: есть ли способ объединить эти два ресурса в качестве службы, которая предоставляет как данные о сотрудниках, так и данные отделов, к которым принадлежит этот сотрудник?


person Korneel    schedule 29.11.2013    source источник


Ответы (2)


Вы можете сделать что-то вроде этого:

angular.module('myApp.services', [])
    .factory('SimpleEmployee', function ($resource) {
        return $resource ('/api/employees/:id', { id: '@id' });
    })
    .factory('Department', function ($resource) {
        return $resource ('/api/departments/:id', { id: '@id' });
    })
    .factory('Employee', ['SimpleEmployee', 'Department', function(SimpleEmployee, Department) {
        return {
            get: function(params) {
                var data = SimpleEmployee.get({id: params.id}, function (employee) {
                    var obj = {
                        employee: employee,
                        departments: []
                    };                        
                    angular.forEach(employee.departmentIds, function (departmentId) {
                        obj.departments.push(Department.get({ id: departmentId }));
                    });
                    return obj;
                });
                return data;
            }
        }
    }]);

И вам не нужно ничего менять в вашем контроллере.

person Beterraba    schedule 29.11.2013
comment
Кажется, это не работает. Он содержит только объект SimpleEmployee, а не объекты отдела. - person Korneel; 02.12.2013
comment
@Korneel Извините. Я копирую и вставляю код вашего ресурса и не вижу вашей ошибки. Вы звонили Department.get({ departmentId: departmentId }), но определили ресурс как $resource ('/api/departments/:id', { id: '@id' });. Отредактировано - person Beterraba; 02.12.2013
comment
Вы также должны изменить var data = Employee... на var data = SimpleEmployee..., но это не проблема. Ресурсы отделов извлекаются правильно, но объект в области не содержит объекты отделов, а только объект SimpleEmployee. Думаю, я упускаю что-то очевидное. - person Korneel; 02.12.2013
comment
Ну, это действительно работает, но я должен сделать это так: Employee.get({ id: 'me' }).then(function (data) { $scope.employee = data.employee; $scope.departments = data.departments; }. Есть ли способ предоставить данные области без использования обратного вызова then? - person Korneel; 03.12.2013
comment
Хорошо, спасибо, я проверил это, но это не решает проблему. - person Korneel; 05.12.2013
comment
В более новых версиях AngularJS вам необходимо развернуть любые объекты промисов на контроллере: /angular/angular.js/commit/ - person Korneel; 05.12.2013

Этот ответ основан на ответе @Beterraba (но пример кода в этом ответе неверен):

Обслуживание:

angular.module('myApp.services', [])
    .factory('SimpleEmployee', function ($resource) {
        return $resource ('/api/employees/:id', { id: '@id' });
    })
    .factory('Department', function ($resource) {
        return $resource ('/api/departments/:id', { id: '@id' });
    })
    .factory('Employee', ['SimpleEmployee', 'Department', function(SimpleEmployee, Department) {
        return {
            get: function(params) {
                return SimpleEmployee.get({id: params.id}).$promise.then(function (employee) {
                    employee.departments = [];
                    angular.forEach(employee.departmentIds, function (departmentId) {
                        employee.departments.push(Department.get({ id: departmentId }));
                    });
                    delete employee.departmentIds;
                    return employee;
                });
            }
        }
    }]);

Контроллер:

Employee.get({ id: 'me' }).then(function (employee) {
    $scope.employee = employee;
});

Начиная с AngularJS 1.2 RC3, вам необходимо развернуть все объекты промисов на контроллере. Я нашел эту информацию здесь.

person Korneel    schedule 05.12.2013