보통 AngularJS를 사용할 때 View에서 사용하는 scope를 제어하기 위해서 Controller를 작성하고 기능별로 모듈화한 Service를 작성한 다음에 Controller에 주입해서 사용한다.
angular.module('myServiceModule', [])
.controller('MyController', ['$scope','notify', function ($scope, notify) {
$scope.callNotify = function(msg) {
notify(msg);
};
}])
.factory('notify', ['$window', function(win) {
var msgs = [];
return function(msg) {
msgs.push(msg);
if (msgs.length == 3) {
win.alert(msgs.join("\n"));
msgs = [];
}
};
}]);
AngualrJS 공식 문서에 나와 있는 Service 예제처럼 notify
라는 서비스를 만들면 이를 MyController
에 주입하고 컨트롤러에서 이를 사용한다. 이 방식으로 체계적으로 모듈화할 수 있고 관심사를 쉽게 분리(Separation of Concerns)할 수 있다. 이렇다 보니 보통은 Service에서 제공하는 기능을 Controller에서 가져다가 사용하고 서로 간의 의존성은 끊는 것이 일반적이다.
그래서 Controller에서 Service로 호출하는 것이 일반적인데 최근에 Socket.IO를 만지다 보니 Service에서 Controller쪽을 호출해야 하는 상황을 겪었다. 웹에선 보통 클라이언트에서 외부로 요청을 보내는 것이 자연스럽지만 최근에는 WebSockets이나 Server Sent등도 존재하므로 서버에서 메시지를 받는 경우도 점점 늘어가고 있다.
이럴 때 서버와 통신을 담당하는 Service를 만들었다면 이를 통해서 메시지를 서버로 보낼 때는 상관없지만, 서버에서 메시지가 왔을 때는 Service에서 Controller 쪽으로 호출해야 하는 상황이 발생한다. 오랜만에 Angular를 만지고 있기도 하지만 이 상황을 겪는 순간 갑자기 코딩이 막혔다. Controller를 Service에 주입하는 건 말도 안 되고 Service에서 이벤트가 발생했을 때 Controller 쪽으로 호출하는 방법이 필요했다. 관련 내용을 찾아보니 Stackoverflow의 "how to emit events from a factory"라는 글이 제일 정리가 잘 되어 있었다.
angular.module('myServiceModule', [])
.factory('serverService', ['$rootScope', function($rootScope) {
return {
messageFromServer: function() {
$rootScope.$broadcast('messageReceived', {text: 'something'});
}
}
}]);
Service에 $scope
를 전달하면 특정 컨트롤러와 의존성을 가지므로 좋은 방법이 아니다. 대신 $rootScope
를 주입해서 $broadcast
로 전체 앱에 이벤트를 시키고 필요한 파라미터를 전달하면 된다.
angular.module('myServiceModule', [])
.controller('MyController', ['$scope', function ($scope) {
$scope.$on('messageReceived', function(event, msg) {
});
}]).
이 이벤트를 받아야 하는 컨트롤러에서는 자신의 $scope
에서 $on
으로 해당 이벤트를 받으면 서비스와 의존성을 갖지 않고도 서비스에서 이벤트를 받을 수 있다.
좋은글 감사합니다~!
저도 service에서 controller 호출이 필요한 상황이 있었는데 많은도움이 되었네요
이 글 관련해서 다른 분들 답변을 보니 서비스내에서 변수를 관리하고 이 변수를 컨트롤러에서 받아서 watch하는 방식도 사용하더군요.
정말 잘보고 갑니다!!