Angular.js는 양방향 바인딩을 지원하기 때문에 컨트롤러나 디렉티브에서 $scope
의 값을 변경해 주면 뷰에서도 변경이 된다. 하지만 이 양방향 바인딩은 Angular.js가 스코프를 인지하고 있을 때만 지원하고 jQuery의 이벤트 리스너 등에서는 스코프를 인지하지 못하므로 scope의 값을 바꾸어도 뷰가 달라지지 않는다.
예를 들어 디렉티브에서 위와 같이 코드로 이벤트 리스너를 추가하더라도 스코프의 값은 달라져도 뷰는 바뀌지 않는다.
그래서 이런 경우는 위처럼 $apply
를 사용해야 제대로 적용이 된다.
하지만 이렇게 사용해서 코딩을 했을 때 컨트롤러와 디렉티브가 복잡하게 얽혀있다 보니 둘의 $apply
가 충돌하는 상황이 발생했다. 어떤 액션이 일어나며서 컨트롤러에서 스코프를 제어하고 있고 컨트롤러에서 발생시킨 동작이 디렉티브까지 이어져서 디렉티브에서도 계속 스코프를 변경하게 된 것이다.(예제를 만들어 볼까 했는데 너무 복잡해 져서..) 그러자 "$apply already in progress"라는 예외가 발생했다. 컨트롤러에서 현재 $apply
가 동작중인데 디렉티브에서 다시 $apply
를 사용하니까 충돌이 난 것이다.
이는 위와 같이 해결할 수 있다. $$phase
로 현재 스코프가 어느 단계에 있는지 알 수 있는데 $$phase
가 $apply
나 $digest
이면 그냥 스코프를 변경하고 그렇지 않으면 $apply
함수를 사용하도록 한 것이다. 이 부분에 관련해서 Angular.js에서 논의도 오간 내용이 있는데 이 논의에 나온 것처럼 safeApply()
같은 함수를 따로 만들어서 사용해도 좋을 것이다.
빨리 Angular.js도 내부 소스를 보기 시작해야 이런 이슈를 쉽게 해결할텐데....
안녕하세요. outsider님!!
최근 angular-summernote가 IE에서 $$phase 오류가 발생되어 수정한 것을 pullrequest 보냈습니다.
Error: [$rootScope:inprog] $digest already in progress
https://github.com/summernote/angular-summernote/pull/34
위에 등록한 링크에서도 scope이 아닌 $rootScope.$$phase를 체크하도록 되어 있네요 ^^
감사합니다.
아 여기도 댓글을 주셨군요.
pull request는 봤는데 저녁정도에 확인해보겠습니다.