Outsider's Dev Story

Stay Hungry. Stay Foolish. Don't Be Satisfied.
RetroTech 팟캐스트 44BITS 팟캐스트

Angular.js 서비스에서 컨트롤러에 이벤트 발생시키기

보통 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으로 해당 이벤트를 받으면 서비스와 의존성을 갖지 않고도 서비스에서 이벤트를 받을 수 있다.

2015/03/31 22:47 2015/03/31 22:47