이 블로그 검색

2014년 12월 26일 금요일

AngularJS : Best practice, 'dot rule'


AngularJS 에서 model을 UI 에 바인딩 시키는 경우, 이른바 'dot rule' 이라고 하는 idiom 이 있다.

"ng-model을 사용 시 dot(.) 이 존재해야 한다. 그렇지 않다면 잘못하고 있는것이다"
"Whenever you have ng-model there’s gotta be a dot in there somewhere. If you don’t have a dot, you’re doing it wrong."

AngularJS Best Practices 에 나오는 내용이고 간단한 예제를 보이면서 설명하고 있다.
이 동영상에 나오는 예제와 동일한 맥락의 다음 예제를 살펴보자.

firefox 에서 JS Bin 이 제대로 표시가 안되는 경우엔 IE, chrome 을 사용해본다.



JS Bin on jsbin.com

scope 구분을 쉽게 하기 위해 붉은색 박스로 처리했다.

<div ng-controller="ParentCtrl">
      ...
      <div ng-controller="ChildCtrl">
      ...
      </div>
</div>

ng-controller 안에 또다른 ng-controller directive를 사용하여, scope가 중첩된 경우이다. ParentCtrl 이 생성한 scope 안에 ChildCtrl scope가 포함된 것을 볼수 있다. 다음처럼 테스트 해본다.

1. 먼저 ParentCtrl 의 input에 입력해본다. ChildCtrl 의 input도 동시에 업데이트 되는것을 볼수있다.
2. 이번엔 ChildCtrl input에 입력해본다.
3. 다시 ParentCtrl 의 input에 입력해본다. 이제 ChildCtrl input은 더이상 업데이트가 되지 않는다.

AngularJS 에서 $scope 객체는 상속 관계를 가진다. 스코프가 중첩되는 경우 하위 scope는 상위 scope를 prototypal inheritance (원형 상속) 하게 된다. 위 예제의 AngularJS scope 상속관계를 평범한 javascript 에서의 상속 관계로 표현 하자면 다음과 같다.

JS Bin

결국 dot rule idiom 이란, javascript의 상속에 있어서의 child가 parent의 property를 숨기는 (hide/shadow) 문제를 방지하기 위한 idiom이라고 할수 있다.

그럼, 다시 처음의 에제로 돌아가 어떤일이 생긴건지 알아보도록 하자.

1. ParentCtrl 의 input에 입력
ChildCtrl 의 scope는 ParentCtrl 의 scope를 상속 받는다. child scope의 stringPrimitive 는 prototype  chain에 의해 parent scope의 stringPrimitive 를 찾게 될것이다. parent scope의 변경 사항이 그대로 child scope에 반영되므로 양쪽 모두 화면이 갱신된다.

2. ChildCtrl input에 입력
이때 일이 틀어지기 시작한다. 이제 child scope는 자신만의 property, stringPrimitive를 갖게 된다. 즉, parent/child 연결이 끊긴다. 이제 더이상 prototype  chain에 의해 parent scope의 stringPrimitive 를 찾지 않게 될것이다. 때문에 ParentCtrl input에는 더이상 갱신되지 않는다.

3. 다시 ParentCtrl 의 input에 입력
마찬가지로 child scope에 고유한 stringPrimitive property가 존재하므로, parent scope의 변경이 child scope에 아무런 영향을 미치지 못한다. 즉, parent/child 연결이 끊긴 상태다.

이처럼 ng-model을 사용할 때, primitive type을 직접 바인딩하게 되는 경우, 중첩된 scope에서 이러한 부작용이 발생하게 되므로, 항상 dot(.)을 사용하는것이 좋다 (물론 중첩되지 않는 경우에도 dot을 사용해야 한다. 이전글 참조). dot rule을 적용해 보자.

JS Bin on jsbin.com

이제 ChildCtrl input에 입력을 하면 child scope에는 객체가 존재하지 않으므로, prototype chain을 따라 parent scope의 objStringPrimitive 에 반영된다. child scope가 자신만의 property를 생성하는 것이 아니다. parent/child 연결이 이제 유지된다.

결론 : scope가 중첩되는 경우, $scope객체는 일반적인 javascript의 prototypal inheritance 을 따르므로, child의 parent shadowing 문제가 발생 가능하다. 이를 방지하려면 primitive type을 직접 바인딩하는것을 피하고 객체를 참조하게 하여 (dot rule idiom), prototype chain 이 동작하게 한다.

참고:
AngularJS Best Practices
https://github.com/angular/angular.js/wiki/Understanding-Scopes
http://nathanleclaire.com/blog/2014/04/19/5-angularjs-antipatterns-and-pitfalls/
http://jimhoskins.com/2012/12/14/nested-scopes-in-angularjs.html

댓글 없음:

댓글 쓰기