AngularJS에서의 핵심 개념인 $scope란 양방향 데이터 바인딩의 핵심이자, 뷰와 컨트롤러를 연결하는 개념이다. 

$scope 는 HTML과 Javascript 를 연결해주는 구조로, 이는 단순한 Javascript 객체에 불과하지만, AngularJS 엔진에 의해 이 객체는 연결된 DOM 요소에서 Data와 Function이 사용되는 공간이라고 할 수 있다.

$scope 는 Javascript Object 이며 view 와 controller 사이를 연결할 수 있도록 몇가지 attribute 들을 포함하고 있다.


모든 AngularJS 로 제작된 Application 은 $rootScope 를 갖고 있으며 이는 ng-app 태그가 포함된 HTML 문서 최상단에 위치하는 $scope 가 된다.

따라서 다른 모든 $scope 들은 글로벌하게 정의되는 $rootScope를 상속하는 계층적인 구조를 이루고 있다. 즉, $rootScope 는 많은 child scope 들을 갖고 있다.

$rootScope 만이 AngularJS App 전체에서 유일한 Global Scope 로 처리가 되기 때문에 다른 AngularJS 의 Feature 들, 가령 Service 나 Factory 등이 $rootScope 를 이용하는 경우가 종종 있다.




위의 그림과 같이 하나의 HTML 에서 여러개의 ng-controller 를 정의할 경우 계층적으로 $scope 를 갖게 되고 이는 자연스럽게 계층 구조를 갖게 된다.


$scope는 뷰와 컨트롤러를 이어주는 다리이면서 연결된 DOM에서 양방향 데이터 바인딩을 처리해준다. 또한 이벤트를 처리할 수도 있다.

이 때, AngularJS 의 각 Controller는 하나의 컨트롤러에 하나의 $scope만을 갖게 된다.

그렇기 때문에 만약 독립된 $scope간 참조가 필요하다면 컨트롤러 간 데이터를 공유해야할 경우에는 Service를 이용한다.


AngularJS 의 실 구현은 대부분 ng-controller 로 명시되는 Controller 에서 수행되는 경우가 많기 때문에, 현재 다루고 있는 $scope 를 이해하고 있는건 매우 중요하다.


다음은 Scope 의 라이프사이클을 설명한다.


$scope 의 LifeCycle


1. 브라우저가 Javascript 를 로딩할 때, AngularJS 의 $injector 를 통해 정의된 Application(ng-app) 에 scope 를 할당한다.


2. 링킹 과정에서 $scope 하위에 $watch 오브젝트들이 등록된다.


3. 연결된 model 의 변화가 감지되면 $scope.$apply() 메서드가 AngularJS 내부에서 호출된다. 작업은 $http, $timeout, $interval 모듈을 이용해서 비동기적으로 이루어진다.


4. 변화가 감지되면 AngularJs 는 $digest cycle 을 rootScope 에서 수행한다. 변경 내용은 모든 child Scope 로 전파되며 당연히 각 $scope 에 정의된 $watch 가 이벤트를 전달받는다.


5. $scope 혹은 child Scope 가 더이상 필요가 없어지면 scope.$destroy 가 이루어지며 root Scope 에 의한 전파가 중단된다. 중단된 $scope 는 향후 가비지 컬렉팅된다.



참조 : https://docs.angularjs.org/guide/scope




최근에 AngularJS 를 이용해서 작업을 하던 도중 알게된 작은 버그이다.

(참고로 버전은 AngularJS 1 버전이고, 크롬에서 발생한 버그이다.)


문제가 된 HTML 은 다음과 같다.



<button class="button btn-danger" ng-click="deleteElement($index)">
<span class="glyphicon glyphicon-remove" aria-hidden="true">Delete</span></button>


위의 코드는 단순히 버튼을 클릭하면 해당 Element 에 대한 정보를 이용해서 ng-click 이벤트를 발생시키는 HTML 코드이다.


이 코드는 아주 잘 작동하지만, HTML 에서 엔터키 입력 시, 아주 사소한 버그를 발견할 수 있었다.


위의 코드에서 같은 scope 로 묶인 Text Box 에서 엔터를 입력하자마자 맨 위 레코드가 삭제되는 버그를 발견하였다.


정확히는 Enter Key 를 입력받아 ng-click 이벤트가 작동한 것이다. 다만, 명시적으로 ng-click 이 호출되지 않은 탓에 Parameter인 $index 는 전달되지 않은듯 하다.


문제의 원인은 <button> 태그에 있었는데, 기본적으로 button 태그의 type 은 "submit" 형이기 때문에, 엔터키 입력에 반응할 수 있다.

(이는 브라우저 별로도 다소 다른 듯 하다.)


문제 해결을 위해서는 다음과 같이 명시적으로 타입을 지정해주면 간단히 해결된다.



<button type="button" class="button btn-danger" ng-click="deleteElement($index)">
<span class="glyphicon glyphicon-remove" aria-hidden="true">Delete</span></button>


혹은 어느정도 규모의 AngularJS 프로젝트를 운용중이라면 directive 로 묶어서 처리하는 것도 좋은 방법이다.



(참고자료 : http://www.jomendez.com/2015/02/16/prevent-ng-click-action-hitting-enter/)

+ Recent posts